疫情期间,时间充足,于是总结自身遇到的问题并学习了一下别人的文章资料,写了一篇前端杂记(含答案),算是给自己的基础一个复习吧

一:html,css部分

1:如何理解html语义化

html语义化是指从代码上展示页面的结构,而不是从最终视觉上来表现结构。「表现形式」html5新标签:

  • header-页眉、footer-页脚、aside-附属信息、nav-导航链接、section、article,
  • caption-表格标题、thead-表头、tbody-表格内容、tfoot-表尾
  • h1~h6,作为标题使用,且重要性递减

「作用」

  • 有利于构建良好的html架构,有利于搜索引擎建立索引和抓取
  • 页面结构清晰,有利于代码的维护和管理
  • 有利于不同设备(盲人阅读器、屏幕阅读器)的解析

2:px,em,rem区别

「px」 相对长度单位,是相当于显示器的分辨率而言的「em」 相对长度单位,相对父元素的字体大小而言的「rem」 相对长度单位,相对html根元素的字体大小而言的,css3新增元素

3:盒子模型

「IE盒子模型」 宽度=内容宽度+padding *2+border *2

「w3c盒子模型」 宽度=内容宽度 通过box-sizing切换,默认为content-box(w3c盒子模型),border-box时为IE盒子模型

4:BFC

块级格式化上下文,让BFC里面的元素与外面元素隔离,使里外元素的定位不会相互影响。触发条件:

  • 根元素
  • overflow不为visible
  • float
  • position:absolute或fixed
  • display:inline-block或table

应用:

  • 防止垂直方向margin重叠
  • 不和浮动元素重叠
  • 清除元素内部浮动

4:target和currentTarget区别

target是事件的真正目标 currentTarget是事件处理程序注册的元素

5:document.ready和window.onload区别

document.ready是dom树加载后执行,而window.onload是整个页面资源加载完后执行,所以document.ready比window.onload先执行

6:事件流

DOM事件流分为三个部分:事件捕获、处于目标、事件冒泡。「事件冒泡」是指事件从执行的元素开始往上层遍历执行「事件捕获」是指事件从根元素开始从外向里执行

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<button id="btn">click Me</button>  
<script>
    let btn=document.getElementById('btn');
    btn.onclick=fucntion(e){
        console.log(e)
    }
</script>
</body>
</html>

点击按钮后,事件冒泡的执行顺序是:button->body->html->document 事件捕获的执行顺序则相反:document->html->body->button

7:doctype作用,严格模式和混合模式的区别

<!doctype>声明位于文档的最前面,在html之前显示。用于告诉浏览器的解析器,用什么文档类型规范来解析文档。 严格模式默认用浏览器支持的最高版本解析,混合模式以宽松的向后兼容的方式解析,doctype不存在或格式不正确时会让文档以混杂模式呈现

8:水平垂直居中

//方法一
display:flex;
justify-content:center;
align-items:center;
//方法二
display:table;
vertical-align:center;
//方法三:适用于已知宽高且父元素定位不为static
postion:absolute;
width:100px;
height:100px;
top:50%;
left:50%;
margin:-50px 0 0 -50px;
//方法四
position:absolute;
top:50%;
left:50%;
transform:translateY(-50%) translateX(-50%);
//方法五:适用于行内元素
display:inline-block;
width:100px;
height:100px;
text-align:center;
line-height:100px;
//方法六:适用于块级元素
display:block;
height:100px;
margin:0 auto;
line-height:100px;

9:回流和重绘区别

回流:当渲染树中元素尺寸、结构或者某些属性发生变化时,浏览器重新渲染部分或全部页面的情况叫回流。 下列元素改变引发回流:

  • getBoundingClientRect()
  • scrollTo()
  • scrollIntoView()或者scrollIntoViewIfneeded
  • clientTop、clientLeft、clientWidth、clientHeight
  • offsetTop、offsetLeft、offsetWidth、offsetHeight
  • scrollTop、scrollLeft、scrollWidth、scrollHeight
  • getComputedStyle()

重绘:当页面中元素样式变化不会改变它在文档流中的位置时,即不会使元素的几何属性发生变化,浏览器会将新样式赋给它并重新绘制页面(比如color、backgroundColor)

注意:频繁回流和重绘会引起性能问题

避免方法:

  • 减少table布局使用
  • 减少css表达式的使用(如calc())
  • 减少DOM操作,用documentFragment代替
  • 将元素设为display:none;操作结束后把它显示回来,因为display:none不会引发回流重绘
  • 避免频繁读取会引发回流重绘的元素,如果需要最好是缓存起来
  • 对复杂动画元素使用绝对定位,使它脱离文档流
  • 减少使用行内样式

二:js部分

1:setTimeout、setInterval区别

两者都是定时器,设定一个150ms后执行的定时器不代表150ms后定时器会执行,它表示代码在150ms内会被加入队列,如果这个时间点队列没有其他逻辑在执行,表面上看代码在精确时间执行了。在队列中有其他逻辑时,代码等待时间会超过150ms「setTimeout」 只执行一次「setInterval」 执行多次,属于重复定时器

2:防抖节流

节流:多次触发事件时,一段时间内保证只调用一次。以动画为例,人眼中一秒播放超过24张图片就会形成动画,假设有100张图片,我们一秒播放100张过于浪费,一秒播放24张就够了。 防抖:持续触发事件后,时间段内没有再触发事件,才调用一次。以坐电梯为例,电梯10s运行一次。如果快要运行时进来一个人,则重新计时。

//节流
function throttle(fn,delay) {
 let timer=null
 return function () {
  if(!timer){
   timer=setTimeout(()=>{
    fn.call(this,arguments)
    timer=null
   },delay)
  }
 }
}
//防抖
function debounce(fn,delay) {
 let timer=null
 return function () {
  if(timer){
   clearTimeout(timer)
  }
  timer=setTimeout(()=>{
   fn.call(this,arguments)
  },delay)
 }
}

3:深浅拷贝

浅拷贝:

  • concat()
  • Object.assign()
  • slice()
  • 手写
function shallowCopy(obj){
 if(typeof obj==='function'&& obj!==null){
  let cloneObj=Array.isArray(obj)?[]:{}
  for(let prop in obj){
   if(obj.hasOwnProperty(prop)){
    cloneObj[prop]=obj[prop]
   }
  }
  return cloneObj
 }
 else{
  return obj
 }
}

深拷贝:

  • JSON.stringfy(JSON.parse())

注意:上面的方法不能解决循环引用,也不能显示函数或undefined

手写深拷贝:

var deepClone=(obj,map=new WeakMap())=>{
  if(map.get(obj)){
   return obj
  }
  let newObj;
  if(typeof obj==='object'&& obj!==null){
   map.set(obj,true)
   newObj=Array.isArray(obj)?[]:{};
   for(let item in obj){
    if(obj.hasOwnProperty(item)){
     newObj[item]=deepClone(obj[item])
  }
 }
   return newObj;
  }
  else {
   return obj;
  }
};

4:继承

关于继承,属于比较多描述才能完整解释的内容,所以请自行百度相关详细资料,不过es6的class多了个extends

//原型链继承
function Parent(){
    this.property=true;
}
Parent.prototype.getValue=function(){
    return this.property;
}
function Son(){
    this.subProperty=false;
}
Son.prototype=new Parent();
let instance=new Son();

原型链继承继承了原型的属性和方法,但是有几个缺点:

  1. 原型链中包括引用类型的值时,会被所有实例共享
  2. 不能实现子类向超类的构造函数中添加属性

由此产生了借用构造函数继承,解决了原型链继承的缺点,它自身又有缺点:不能实现函数复用

//借用构造函数继承
function Parent(){
    this.property=true;
}
function Son(){
    Parent.call(this);
}
//组合继承
function Parent(){
    this.property=true;
    this.colors=['red','purple','orange']
}
Parent.prototype.getPro=function(){
    return this.property;
}
function Son(property,name){
    Parent.call(this,property);
    this.name=name;
}
Son.prototype=new Parent()

组合继承避免了原型链和借用构造函数的缺陷,是最常用的继承之一

//原型继承
var a = {
 friends : ["yuki","sakura"]
};
var b = Object.create(a);
b.friends.push("ruby");
var c = Object.create(a);
c.friends.push("lemon");
alert(a.friends);//"yuki,sakura,ruby,lemon"

原型继承缺点跟原型链继承一样,也是引用类型的属性会被所有实例共享

//寄生式继承,可以类比设计模式的工厂模式
function createAnother(obj){
 var clone = object(obj);
 clone.sayHi = function(){
  console.log("hello");
 };
 return clone;
}

寄生式继承不能做到函数复用

//寄生组合式继承
function Parent(name){
    this.name=name;
    this.colors=['red','white','gray']
}
Parent.prototype.getName=function(name){
    this.name=name
}
function Son(name,age){
    Parent.call(this,name);//第二次调用Parent()
    this.age=age;
}
Son.prototype=new Parent()//第一次调用Parent()
Son.prototype.constructor=Son;
Son.prototype.getAge=function(){
    return this.age;
}

寄生组合式继承避免了在子实例上创建多余的属性,又能保持原型链不变,还能正常使用instanceof()和isPrototypeOf(),是最理想的继承方式。es6方法的继承:通过extends实现

class Parent(){
    constructor(){}
}
class Son extends Parent(){
    constructor(){
        super()
    }
}

5:es6新特性

很多,比如Promise,箭头函数、数组扩展:includes()、find()、findIndex()...,Symbol、Map、Set... 我就不罗嗦了,经常用的就那几个,请自行百度,或查看我的另外一篇文章,那里面有部分用法   https://www.cnblogs.com/shadow110/p/14245242.html

6:es6的class的es5的类有什么区别

  • es6 class内部定义的方法都是不可枚举的
  • es6 class必须用new调用
  • es6 class不存在变量提升
  • es6 class默认使用严格模式
  • es6 class子类必须在父类的构造函数中调用super(),才有this对象;而es5是先有子类的this,再调用父类的方法应用再在this上面

7:数组去重

//方法一 使用ES6的Set
function filterArr(arr) {
 return new Set(arr)
}
//方法二:filter+indexOf()判断,如果数字不是第一次出现则被过滤
function filterArr2(arr){
 let newArr=arr.filter((item,index)=>{
  return arr.indexOf(item)===index
 })
 console.log(newArr)
}
//方法三:双重for循环
function filterArr3(arr){
 let isRepeat,newArr=[];
 for(let i=0;i<arr.length;i++){
  isRepeat=false
  for(let j=i+1;j<arr.length;j++){
   if(arr[i]===arr[j]){
    isRepeat=true
    break
   }
  }
  if(!isRepeat){
   newArr.push(arr[i])
  }
 }
 return newArr
}
//方法四:哈希表
function filterArr4(arr){
 let seen={}
 return arr.filter(function (item) {
  return seen.hasOwnProperty(item)?false:(seen[item]=true)
 });
}
//方法五:sort排序,相同的数字会排在相邻n个位置
function filterArr5(arr){
 let lastArr=[]
 const newArr=arr.sort((a,b)=>{
  return a-b
 })
 for(let i=0;i<newArr.length;i++){
  if(newArr[i]!==newArr[i+1]){
   lastArr.push(newArr[i])
  }
 }
 return lastArr
}

8:this

this绑定函数的执行上下文,谁调用它,它就指向谁。分为默认绑定、显式绑定、隐式绑定、apply/call/bind绑定、new绑定和箭头函数绑定

注意:

默认绑定:严格模式下this指向undefined,非严格模式this指向window

function foo() {
    console.log(this.a)
}
var a=2
foo()

执行结果是什么?显然是2,此时使用的默认绑定规则(非严格模式),this指向的是window,因此调用this.a等于调用window.a,输出结果2。如果使用严格模式,结果又会是什么?

function foo() {
    'use strict'
    console.log(this.a)
}
var a=2
foo()

此时this不再指向window,而是undefined,因此调用this.a会抛出一个错误,Cannot read property 'a' of undefined

隐式绑定 下面这段代码的输出是什么?

function foo() {
    console.log(this.a)
}
var obj={
    a:2,
    foo:foo
}
obj.foo()

当foo函数被调用时,它被obj对象拥有,因此输出2

注意:对象引用只有最后一层会影响调用位置

function foo() {
    console.log(this.a)
}
var obj2={
    a:42,
    foo:foo
}
var obj1={
    a:2,
    obj2:obj2
}
obj1.obj2.foo()//42

call、apply、bind都可以改变this的指向,但是apply接收参数数组,call接收的是参数列表 bind接收的是参数列表,但是apply和call调用就执行,bind需要手动执行 箭头函数绑定:箭头函数的this是父作用域的this,不是调用时的this,其他方法的this是动态的,而箭头函数的this是静态的

window.name='a'
const obj={
    name:'b',
    age:22,
    getName:()=>{
        console.log(this)
        console.log(this.name)
    },
    getAge:function(){
        setTimeout(()=>{
            console.log(this.age)
        })
    }
}
obj.getName();//window a
obj.getAge();//22

优先级:箭头函数>new绑定>显示绑定/apply/bind/call>隐式绑定>默认绑定

9:箭头函数和普通函数区别

  • 箭头函数没有prototype,所以箭头函数本身没有this
  • 箭头函数的this指向在定义的时候继承自外层第一个普通函数的this
  • 箭头函数没有arguments,普通函数有
  • 使用new调用箭头函数会报错
  • 不可以使用yield命令,因此箭头函数不能用作 Generator 函数。

10:new的原理

var obj={};
obj._proto_=F.prototype;
F.call(obj);
  1. 创建一个空对象
  2. this变量引用该对象,同时还继承了这个函数的原型
  3. 属性和方法被加入到引用的对象里
  4. 新创建的对象由this引用,最后隐式返回this

11:浏览器事件循环和node事件循环

浏览器事件循环:

  1. 同步任务在主线程执行,在主线程外还有个任务队列用于存放异步任务
  2. 主线程的同步任务执行完毕,异步任务入栈,进入主线程执行
  3. 上述的两个步骤循环,形成eventloop事件循环 浏览器的事件循环又跟宏任务和微任务有关,两者都属于异步任务。

js异步有一个机制,就是遇到宏任务,先执行宏任务,将宏任务放入任务队列,再执行微任务,将微任务放入任务队列,他俩进入的不是同一个任务队列。往外读取的时候先从微任务里拿这个回调函数,然后再从宏任务的任务队列上拿宏任务的回调函数

宏任务:

  • script
  • 定时器 setTimeout setInterval setImmediate

微任务:

  • promise
  • process.nextTick()
  • MutationObserver

node事件循环:

  1. timer阶段
  2. I/O 异常回调阶段
  3. 空闲预备阶段
  4. poll阶段
  5. check阶段
  6. 关闭事件的回调阶段

关于具体的事件循环相关,请自行百度或者观看视频,因为这算是v8或者node的核心知识,只言片语是讲不完的,得详细的学习了解才能看懂我上面的简略介绍的事件循环的知识点

12:手写promise

简易版

function myPromise(executor) {
    let self=this;
    self.status='pending';
    self.value=undefined;
    self.reason=undefined;
    function resolve(value) {
        if(self.status==='pending'){
            self.value=value
            self.status="resolved"
        }
    }
    function reject(reason) {
        if(self.status==='pending'){
            self.reason=reason
            self.status=status
        }
    }
    try{
        executor(resolve,reject)
    }
    catch (e) {
        reject(e)
    }
}

13:手写bind

Function.prototype.myBind=function(context,...args){
   const fn=this
   args=args?args:[]
   return function newFn(...newFnArgs) {
       if(this instanceof newFn){
           return new fn(...args,...newFnArgs)
       }
       return  fn.apply(context,[...args,...newFnArgs])
   }
}

 

14:手写call、apply

Function.prototype.myCall=function(context,...args){
    context=context||window
    args=args?args:[]
    const key=Symbol()
    context[key]=this
    const result=context[key](...args)//通过隐式绑定的方式调用函数
    delete context[key]//删除添加的属性
    return result//返回函数调用的返回值
}
Function.prototype.myApply=function(context,args){
    context=context||window
    args=args||[]
    const key=Symbol()
    context[key]=this
    const result=context[key](...args)
    delete context[key]
    return result
}

三:vue部分

1:vue的双向绑定原理

vue的双向绑定是通过数据劫持和发布者-订阅者模式实现的,数据劫持又是通过Object.defineProperty()实现的
Object.defineProperty(data,'a',{
    enumerable:true,//是否可枚举
    writable:true,//是否可写
    configurable:true,//是否可配置
    get(){
        return this.a//读取data对象的a属性时,触发get方法
    },
    set(val){
        this.a=val;//修改data对象的a属性时,触发set方法
    }
})
mvvm的数据变化更新视图,是通过Object.defineProperty()实现的;视图更新变化数据,是通过事件监听实现的。
发布者-订阅者的实现过程:
1. 实现一个监听器Observer,劫持并监听所有属性,如果有变化,就通知订阅者
2. 实现一个订阅者Watcher,收到属性的变化通知并执行响应的函数,从而更新视图
3. 实现一个解析器Compiler,可以扫描并解析每个节点的相关指令,初始化模板数据和对应的订阅器

2:vue的指令有哪些

v-if 用于条件渲染
v-show 用于条件渲染,两者的区别请参考下一个问题
v-for 用于列表渲染
v-on  监听事件
v-bind 动态绑定
v-html 渲染html元素
v-model 数据双向绑定

3:v-if和v-show区别

v-if 是惰性的,只有条件为真时才会切换,为假时什么也不做。确保切换过程中的事件监听器和子组件适当的被销毁和重建,适用于运行条件很少改变的场景。
v-show 不管条件是否为真,总是会被渲染,适用于频繁切换的场景

4:v-for和v-if为什么不能放于同一级

v-for优先级高于v-if,放于同级可能会重复渲染两次v-if,建议把v-for放于v-if所在的外层元素

5:nextTick

原理:eventloop事件循环 在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。(涉及到了事件循环的顺序,可以自行了解事件循环后再深入理解nextTick)

6:v-for中key的原理

key 主要用在 Vue 的虚拟 DOM 算法,在新旧 nodes 对比时辨识 VNodes。不指定key时,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试
就地修改/复用相同类型元素的算法。而使用 key 时,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。
有相同父元素的子元素必须有独特的 key。重复的 key 会造成渲染错误。

7:vue的生命周期

1.beforeCreate
 初始化界面前
2.created
  初始化界面后,拿到data,props,methods、computed和watch
3.beforeMount
 渲染dom前
4.mounted
 渲染dom后,拿到$el
5.beforeUpdate
 更新前
6.updated
 更新后,拿到更新后的dom
7.beforeDestroy
 卸载组件前
8.destroyed
 卸载组件后
9.activated
 被 keep-alive 缓存的组件激活时调用
10.deactivated
 被 keep-alive 缓存的组件停用时调用
11. errorCaptured
 当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例
 以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播。

具体示例:

<!--  -->
<template>
  <div class=""></div>
</template>

<script>
// 这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
// 例如:import 《组件名称》 from '《组件路径》';

export default {
// import引入的组件需要注入到对象中才能使用
components: {},
data () {
// 这里存放数据
return {

}
},
// 监听属性 类似于data概念
computed: {},
// 监控data中的数据变化
watch: {},
// 方法集合
methods: {

},
// 生命周期 - 创建完成(可以访问当前this实例)
created () {

},
// 生命周期 - 挂载完成(可以访问DOM元素)
mounted () {

},
// 生命周期 - 创建之前
beforeCreate () {},
// 生命周期 - 挂载之前
beforeMount () {},
// 生命周期 - 更新之前
beforeUpdate () {},
// 生命周期 - 更新之后
updated () {},
// 生命周期 - 销毁之前
beforeDestroy () {},
// 生命周期 - 销毁完成
destroyed () {},
// 如果页面有keep-alive缓存功能,这个函数会触发
activated () {}
}
</script>
<style lang='scss' scoped>
//@import url(); 引入公共css类

</style>

8:父子组件通信

父传子:prop 
子传父:$emit
父子通信:
+ eventbus
+ vuex
+ ref结合$parent或 $children
跨层级较多:provide/inject  //具体可参照我的另一篇文章 https://www.cnblogs.com/shadow110/p/14302700.html

9:computed和watch区别

computed用于计算属性,只有它依赖的值改变才会触发,且这个值有缓存

watch用于监听一个属性的变化,属性变化就会触发

10::Vnode的diff算法原理

虚拟dom是对真实dom的一种映射,新旧Vnode比较同层级的节点,然后根据两者的差异只更新有差异的部分,生成新的视图,而不是对树进行逐层搜素遍历,因此时间复杂度是O(n)。 虚拟dom可以减少页面的回流和重绘,提升性能

四:webpack相关

1:webpack运行流程

分为初始化、编译、输出三个阶段.「初始化」

  1. 从配置文件和shell文件读取、合并参数;
  2. 加载plugin
  3. 实例化compiler

「编译」

  1. 从entry发出,针对每个module串行调用对应loader翻译文件内容
  2. 找到module依赖的module,递归进行编译处理

「输出」

  1. 把编译后module组合成chunk
  2. 把chunk转换成文件,输出到文件系统

 2:webpack性能优化

优化可以从两个方面考虑,一个是优化开发体验,一个是优化输出质量。「优化开发体验」

  • 缩小文件搜索范围。涉及到webpack如何处理导入文件,不再赘述,不会的可以自行搜索。 由于loader对文件转换操作很耗时,应该尽量减少loader处理的文件,可以使用include命中需要处理的文件,缩小命中范围。
  • 使用DllPlugin,提升构建速度
  • 使用happyPack开启多线程
  • 使用UglifyJs压缩代码(只支持es5),uglifyes支持es6,两个插件不能同时开启。使用ParalellUgifyPlugin开启多个子进程压缩,既支持UglifyJs又支持uglifyes
  • 使用自动刷新:监听到代码改变后,自动编译构建可运行代码并刷新页面
  • 开启模块热替换:在不刷新网页的同时实现实时预览

「优化输出质量」 减少首屏加载时间

  • 区分环境
  • 压缩代码
  • CDN加速
  • 使用Tree shaking
  • 提取公共代码
  • 按需加载

提升流畅度,即代码性能:

  • 使用PrePack优化代码运行时的效率
  • 开启Scope Hoisting,让webpack打包出来的代码更小、运行更快

3:loader的原理

loader能把源文件翻译成新的结果,一个文件可以链式经过多个loader编译。以处理scss文件为例:

  • sass-loader把scss转成css
  • css-loader找出css中的依赖,压缩资源
  • style-loader把css转换成脚本加载的JavaScript代码

4:plugin原理

plugin用于扩展webpack功能。

  • webpack启动后,在读取配置时会先执行new BasicPlugin(options)初始化一个BasicPlugin获得它的实例
  • 调用BasicPlugin.apply(compiler)给插件实例传递compiler对象
  • 插件实例获取compiler对象后,通过compiler.plugin(事件名,回调函数)监听webpack广播出的事例

五:http相关

1:url从输入到输出的过程

1. 构建请求
构建请求行,请求行包括请求方法、请求http版本、URI
Get/Http/1.0
2. 查找强缓存
检查强缓存,命中则直接使用,否则检查协商缓存
3. DNS解析
域名与IP地址映射
4.建立tcp连接
chrome限制同一域名下最多6个tcp连接
+ 通过三次握手建立连接
三次握手过程:
1.客户端向服务器发送连接请求,传递一个数据包syn,此时客户端处于SYN_SEND状态
2.服务器接收syn报文后,会以自己的syn报文作为应答,传递数据包syn+ack,此时服务器处于SYN-REVD状态
3.客户端接收syn报文后,发送一个数据包ack,此时客户端处于ESTABLISHED状态,双方已建立连接
+ 进行数据传输
+ 通过四次挥手断开连接
四次挥手过程:
1. 客户端发送一个FIN报文,报文中指定一个序列号,此时客户端处于FIN_WAIT1状态,等待服务器确认
2. 服务器接收到FIN后,会发送ACK确认报文,表明已经收到客户端报文,此时服务端处于CLOSE_WAIT2状态
3. 服务器发送FIN,告诉客户端想断开连接,此时服务端处于LAST_CHECK阶段
4. 客户端收到FIN后,一样发送一个ACK作为应答,此时客户端处于TIME_WAIT阶段。需要过一段时间确认服务端收到自己的ACK报文
后才会进入CLOSED状态
5.发送http请求
6.网络响应
7.浏览器解析和渲染
分为构建dom树、样式计算、生成布局树。
8.生成布局
触发回流和重绘

2:介绍下半连接队列

服务器第一次接收到客户端的SYN后,会处于SYN-REVD阶段,此时双方还没有建立完全的连接,
服务器会把此种状态下请求连接放在一个队列里,我们把这种队列称为半连接队列
已经完成三次握手并建立连接,就叫全连接队列

3:http和https区别

  1. http基于TCP/IP协议,https基于SSL/TLS协议
  2. http默认端口号为80,https默认端口号为443
  3. https安全性更强,需要CA证书
  4. https可以防止运营商劫持

注意:可以详细了解https的通信过程,涉及对称加密和非对称加密

4:tcp和udp区别

  1. tcp只能一对一通信,udp可以一对一、一对多、多对多通信,即支持多播和广播
  2. tcp首部开销消耗32字节,udp仅消耗8个字节
  3. tcp适合对数据安全性要求高的场景,比如文件传输,udp适合对数据实时性要求高的场景,比如视频通话、语音通话
  4. tcp是有状态连接,udp是无状态的连接
  5. tcp-可靠传输 udp-不可靠传输
  6. tcp-面向字节流 udp-面向报文

5:tcp怎么保证可靠性

1. 超时重传机制
2. 对失序数据进行重排序
3. 应答机制
4. 滑动窗口
5. 拥塞控制

6:http请求有哪几种

「http1.0」:get、post、head「http1.1」:put、delete、connect、trace、options「简单请求」:

请求method只能是get、post、head
请求头只能是accept/accept-language/content-language/content-Type
content-Type只能是text/plain、multipart/form-data、application/x-www-form-urlencoded

7::http1.0|http1.1|http2.0

「http1.0」:

  1. 完成连接即断开,导致重新慢启动和三次握手
  2. 线头阻塞,导致请求间相互影响

「http1.1」

  1. 用keep-alive支持长连接
  2. 用host字段指定对应的虚拟站点
  3. 新增功能: 断点续传、身份认证、状态管理、cache缓存->cache-control、expires、last-modified、etag

「http2.0」

  1. 二进制分帧层:应用层和传输层
  2. header头部压缩
  3. 服务端推送
  4. 多路复用

注意:二进制分帧层可以扩展到计算机网络的OSI参考模型,请自行学习

8:客户端缓存

客户端缓存分为cookie、localStorage、sessionStorage、indexedDB,请自行学习

9:浏览器缓存

「强缓存」不向http发送请求,返回状态码304. 检查强缓存有两个字段: http1.0使用expires,代表过期时间,但是服务器时间和客户端时间可能不一致。为了弥补这个缺点,http1.1使用cache-control的max-age字段,cache-control有多个指令

  • public 允许客户端和代理服务器缓存
  • private 允许客户端缓存
  • no-store 不使用缓存
  • no-cache 使用协商缓存 两个字段都存在,cache-control优先级高于expires

「协商缓存」 向http发送请求,返回状态码200 检查协商缓存有两个字段: http1.0使用last-modified,即最后修改时间。

  1. 在浏览器向服务器发送请求后,服务器会在响应头上加上这个字段
  2. 浏览器接收后,如果再次请求,会在请求头上携带If-Modified-Since
  3. 服务器拿到If-Modified-Since字段后,会和服务器中该资源的最后修改时间对比,如果请求头中这个值小于最后修改时间,更新资源;否则返回304,告诉浏览器直接使用缓存

http1.1使用etag,etag是服务器根据当前文件内容,给文件生成的唯一标识,只要内容改变,这个值就会变。etag优先级高于last-modifed 缓存位置,按优先级从高到低分别是:

  • service worker
  • memory cache
  • disk cache
  • push cache

10:http状态码

列举一些常见状态码吧,剩下的请自行学习

200-请求成功
301-永久重定向
302和307-临时重定向
400-当前请求不能被服务器理解或请求参数有误
401-请求需要认证或认证失败
403-服务器禁止访问
404-资源未找到
405-方法未允许
500-内部服务器错误
502-网关错误
503-服务器处于超负载或停机维护

11:nginx

ngnix是个高性能反向代理服务器,有以下作用:

  • 解决跨域
  • 请求过滤
  • 配置gzip
  • 负载均衡
  • 静态资源服务器

ngnix解决跨域的原理:

  • 把后端域名设为前端服务的域名,然后设置相应的location拦截前端需要跨域的请求,最后将请求代理回服务端的域名
  • ngnix实现负载均衡的策略:轮询、最小链接数、最快响应时间

六:web安全

1:xss

跨站脚本攻击,指攻击者在网页上注入恶意的客户端代码,通过恶意脚本对客户端网页进行篡改,从而在用户浏览网页时, 对客户端浏览器进行控制或获取用户隐私数据的方式「防范」

  1. httpOnly防止截取cookie
  2. 用户输入检查
  3. 用户输出检查
  4. 利用CSP(浏览器的内容安全策略)

2:csrf

跨站请求伪造,劫持受信任用户向服务器发送非预期请求的方式。「防范」

  1. 验证码
  2. referer check
  3. 增加token验证

3:二次封装axios

1.新建一个axios对象,定义好字段并设置默认值,比如超时时间、请求头
2.定义过滤字符串方法,过滤服务端为空字符串或null的属性
3.请求拦截器调用过滤字符串方法,遍历url上的字段,如果为数组或对象转为JSON对象
4.响应拦截器捕获错误,根据http状态码进行不同的处理,比如401跳转登陆页面,403返回您没有权限,502返回系统正在升级中,请稍后重试,
504返回系统超时,并弹出对应的消息提示框。消息提示框自定义

 

4:axios调用流程

查看axios源码,axios调用流程实质是Axios.prototype.request的实现,调用过程如下:
1.判断传入参数config是否是字符串,是则设置url,否则设置config为对象
2.调用mergeConfig方法,合并默认参数和用户传入的参数
3.如果设置了请求方法,将其转为小写,否则设置请求方法为get
4.将用户设置的请求和响应拦截器、发送请求的dispatchRequest组成promise链,最后返回promise实例。
这一步保证先执行请求拦截器,再执行请求,最后执行响应拦截器

 

六:web项目(项目汇报---前端篇)

从一到两个比较有代表性的项目上来总结的话,可以用SWOT方法,简要介绍项目的背景,项目的主要的技术难点,如何解决的,项目做完后的效果。我主要讲的是怎么推动Jenkins自动化部署在前端组里的应用以及前后端分离后,前端分模块开发过程中的相关规范,具体规范可参照阿里官方标准的一本书叫(阿里巴巴java开发手册 第二版)

七:总结(前端篇)

以上回顾的知识点以及技巧,均是个人心得以及部分摘抄自官方或网上的资料,只讲到了知识点,并没有很深入的讲某一个。因为每一个大模块都是有很深的知识可挖,本文章知识简单回顾过去所学的东西,故很多知识点只是简单提及,想深入学习的同学请自行百度,买书或者看视频

 

ok

回顾完毕

 

posted @ 2021-01-21 11:04  时光待我如旅人  阅读(134)  评论(0)    收藏  举报