前端Vue和计网面试题总结

193 阅读51分钟

@TOC


Vue面试题总结

一、Vue.js的优点

命令式操作DOM难以维护,所以vue.js提供了声明式操作DOM的能力。 Vue允许你将一个网页分割成可复用的组件,每个组件都有自己的HTML,CSS,JS来渲染网页中的一个对应的位置。 Vue.js是一个渐进式框架,也就是框架分层,你可以根据需求来选择。 视图层渲染->组件机制->路由机制->状态管理->构建工具

二、vue组件通信方式

(1)父子通信:

父传子: 父组件通过props的方式向子组件传递数据(只能从父组件到子组件,也就是单向数据流,而且prop只可读,不可修改); 在这里插入图片描述

(2)兄弟组件通信:

在这里插入图片描述

(3)跨级通信:

在这里插入图片描述

三、vuex

(1)项目中有使用vuex吗?

项目中存储用户登录时后台返回的token,用户信息,收藏的商品,购物车中的物品等等都使用了vuex。

(2)Vuex是什么?

Vuex是一个专门为vue.js应用程序开发的状态管理模式,解决了不同组件之间的数据共享数据持久化

  • Vuex有五个核心部分State:保存着仓库中的变量(相当于组件的data) Mutations:是同步函数,只能通过mutations来修改state Actions:是异步方法,提交mutation,通过mutation来修改state Getters:可以理解为计算属性,用于简化仓库数据(action和getter相当于用来修改数据的方法) Module:状态树过大时可以将store分割成module,每个module都有自己的state,mutation,action,getter。

(3)(既然组件有data,计算属性,也能写方法改写数据)为什么要使用vuex?

从组件角度来看,如果组件要管理维护的数据不多,我们可以不用vuex;但需要管理的数据一多,组件内的代码就很杂乱。如果多个组件都需要同一个数据,那在这些组件中都要写一次。所以不如数据放到仓库里管理,组件里写组件的内容,管理数据交给vuex完成。在后期对数据进行维护时,只需要到仓库里修改就行。

(4)如何使用Vuex?

在actions里面处理异步和业务逻辑,提交mutation,在mutation里面修改state,state会被渲染到组件页面;在组件内部用dispatch派发action。(然后可以在computed内使用辅助函数从仓库拿数据) 在这里插入图片描述

四、Package.json是干嘛的

这个文件存储的是开发时依赖和运行时依赖的包的版本号,以后分享项目的时候,直接npm install就可以安装对应的依赖。

五、导航守卫

导航表示路由正在发生改变限制路由的跳转就用导航守卫。导航守卫分为三种:全局守卫,路由独享守卫,组件内守卫。 在这里插入图片描述

六、Vue的响应式原理、双向绑定原理,MVVM原理(数据劫持+发布订阅者模式)

(1)响应式/双向绑定原理

当把一个普通的JavaScript对象传入Vue实例作为data选项,object可以通过js中的object.defineproperty方法(可以侦测到对象的变化)将属性转换成getter,setter的形式来追踪变化。但是这个只能侦测到某一个属性。所以vue封装了一个observer类,通过递归将数据中的所有属性都侦测到,也就是把每一个属性都转换成getter和setter的形式了。 传入data中的数据若是数组,因为它是通过方法来改变内容的,所以要通过创建拦截器去覆盖数组原型的方式来追踪变化。 当外界通过watcher(也就是依赖)读取数据时,会触发getter从而将watcher添加到依赖(Dep类)中。当数据变化时,会触发setter,从而向Dep类中的依赖发送通知。 Watcher接收到通知后,会向外界发送通知变化,通知外界后可能会触发视图更新,也有可能触发用户的某个回调。 在这里插入图片描述

(2)Vue2响应式的局限性:

在这里插入图片描述 在这里插入图片描述

(3)vue2.x和vue3.x之间的区别是什么?

(1)数据劫持方式改变。Vue3.x用proxy代替了object.defineproperty。可以直接监听数组的变化和对象的增删。 (2)Vue3的组件可以拥有多个根节点。 (3)Vue2使用选项类型API,vue3使用合成型API(composition API),相对于旧的API使用属性来分组,合成型API把相同逻辑的代码组织到一起,方便大型项目的维护。

(4)Object.defineproperty的其他用法

七、讲一下虚拟DOM。(为什么引入;什么是虚拟DOM;原理;patch/diff)

(1)虚拟DOM

DOM操作非常昂贵,为了减少对DOM的操作,vue.js将DOM抽象成了一个以js对象为节点的虚拟DOM树,用VNode节点模拟真实DOM节点,可以对虚拟DOM节点进行创建,删除以及修改等操作,这个过程不需要操作真实DOM。当数据发生改变时,Vue.js会使用diff算法比对oldvnode和vnode,得出最小的修改单位,对真实DOM打补丁。 当数据进行更新的时候,会触发update函数,该函数会接收一个VNode对象,利用_patch_方法对比VNode和OldVNode,并对真实的DOM打补丁,_patch_的核心就是diff算法。diff算法是通过同层的树节点进行比较,而不是对树进行逐层搜索,时间复杂度只有log(n)。

(2)diff算法

(1)使用sameVNode函数判断两个节点是否为相同节点(对比标签名tag,属性key,是否为注释节点iscomment 是否相同),不是相同节点则在真实DOM上创建新的DOM,移除旧的DOM;是相同节点则调用patchVnode函数来比较节点。 (2)比较节点的过程:

  • 找到VNode和OldVnode对应的真实DOM,即el,判断Vnode和oldVnode是否指向同一节点,是就返回。如果两者都有文本节点且不相等,将el的文本节点设置为Vnode的文本节点。
  • 如果oldVnode有子节点,Vnode没有,则删除el的子节点;如果oldVnode没有子节点,Vnode有,将Vnode的子节点真实化后添加到el;如果都有子节点,就调用updateChildren函数比较子节点。

(3)比较子节点的过程,也就是调用了updateChildren函数之后:

  • 先将Vnode的子节点Vch和OldVnode的子节点oldch提取出来。
  • vch和oldch都在首尾设置了startIdx和endIdx变量,2个变量相互比较。
  • 若四种比较都未匹配,如果设置了key,利用key进行比较。比较过程中变量会向中间移,出现startIdx>endIdx则表示至少存在一个遍历完成,比较就结束了。(key和四种比较过程在下面)
  • 四种比较: (1)比较ns(new startIdx)和os(old startIdx):比较的时候都是用sameVnode来比较,如果返回true,也就是相同节点,调用patchVnode函数对比节点,然后两个指针都向后移。 (2)比较ne(new endIdx)和oe(old endIdx):和刚才的ns和os比较相似,然后两个指针都向前移动。 (3)比较os(old startIdx)和ne(new startIdx):比较的时候也用sameVnode,如果返回true,就将os指向的节点移动到oe指向节点的后面,同时对该节点和ne指向的节点调用patchVnode函数对比节点,os的指针向后移动,ne的指针向前移动。 (4)比较oe和ns:和刚才的os和ne比较相似。 当出现ns>ne或者os>oe就结束比较。

(3)写key的作用是什么?

为列表渲染设置了key属性,可以标识一个节点唯一的id。依靠key,可以更准确更快的拿到oldvnode中对应的vnode节点。

七、简述一下babel的编译过程(babel的执行过程)

(1)Babel的基本概念

Babel是一个JS编译器,是一个工具链。主要用于将采用ES2015+语法编写的代码转换为向后兼容的JS语法,从而在老版本的浏览器中执行。Babel的本质就是操作AST来完成代码的转义。

(2)Babel的工作过程可以分为三部分:

解析(将模板解析成AST)---->转换(将高版本语法的AST转换成支持低版本语法的AST)---->生成(将AST转换成字符串形式的低版本代码);经过这三个阶段,代码就被babel转译成功了。 AST(抽象语法树Abstract syntax tree): 用JS中的对象来表示节点树,对象中的属性用来保存节点所需的各种数据,和vnode很像。

{
Tag:’div’,
Type:1,
Parent:undefined,
Children:[
{
Ta**加粗样式**g:’p’,
Type:1,
}
]
}

八、Vm.$nextTick

(1)作用:

将回调延迟到下次DOM更新周期(也就是下次微任务执行时更新)之后执行。Vm.$nectTick其实是将回调添加到微任务中。当数据更新了,在dom中渲染后,自动执行该函数.

(2)使用场景:

当更新了数据后,要对新的DOM做一些操作,但是这时我们其实获取不到更新后的DOM,因为还没有重新渲染。这个时候我们要使用nextTick方法。

(3)NextTick()原理;

(4)为什么使用vue.nextTick()

通过数组callbacks存储用户注册的回调,声明了变量pending标记是否已经向任务队列中添加了一个任务。每当向任务队列中插入任务时,将pending设置为true,每当任务执行时将pending设置为false,这样就可以通过pending的值来判断是否需要向任务队列中添加任务。 会有一个flushCallbacks函数,它就是那个被注册的任务。当这个函数被触发时,会将callbacks中的所有函数依次执行,然后清空callbacks,并将pending设置为false.也就是一轮事件循环中flushCallbacks只会执行一次。 然后会有一个microTimerFunc函数,它使用promsie.then将flushCallbacks添加到微任务队列中。 当执行nextTick函数注册回调时,会先将回调函数添加到callbacks中,然后使用pending判断是否需要向任务队列中新增任务。

JS的事件循环机制和vue.JS的异步更新。

js是一个单线程的脚本语言。当执行栈(执行环境的栈)中所有任务都执行完毕后,去看微任务队列中是否有事件存在,如果存在,则依次执行微任务队列中事件的回调,直到微任务队列为空。然后去宏任务队列中取出一个事件,把对应的回调加入当前执行栈,当执行栈中所有任务都执行完毕后,再去检查微任务队列中是否有事件存在。这个循环的过程就是事件循环。

由于Vue DOM更新是异步执行的,即修改数据时,视图不会立即更新,而是会监听数据变化,并缓存在同一事件循环中,等同一数据循环中的所有数据变化完成之后,再统一进行视图更新。为了确保得到更新后的DOM,所以设置了 Vue.nextTick()方法。

九、Vue.js为什么使用异步更新队列

在vue.js中,当状态发生变化时,watcher会得到通知,然后出发虚拟DOM的渲染流程。而watcher触发渲染的这个操作是异步的。Vue.js中有一个队列,每当需要渲染的时候,会将watcher推送到这个队列,在下一次事件循环中再让watcher触发渲染的流程。

原因:变化侦测的通知发送给组件,组件内用到的所有状态的变化都会通知到同一个watcher(依赖)。然后虚拟DOM对整个组件进行对比,并修改DOM。也就是说,如果同一轮事件循环中有两个数据发生变化,那么组件的watcher会收到两份通知。从而进行两次渲染。这样会造成资源浪费。 Vue.js实现方式是将收到通知的watcher实例添加到队列中,缓存起来,并在添加到队列之前检查是否已存在相同的watcher。只有不存在时,才将watcher实例添加到队列中。然后在下一次事件循环中,让队列中的watcher触发渲染流程并清空队列。这样可以保证在同一事件循环中有多个状态发生变化,watcher最后也只执行一次渲染流程。

10、生命周期

vue实例从创建到销毁的过程就称为生命周期。 (1)在初始化阶段,也就是通过new Vue创建实例到created生命周期函数执行之后的这段时间里,首先初始化属性与事件,然后通过callback函数触发生命周期钩子beforecreate,随后初始化provide/inject和状态。状态指的是props,methods,data,computed,watch。接着触发生命周期钩子created。 (2)在这里插入图片描述

(3)在挂载过程中,实例会被挂载到DOM元素上,也就是将模板渲染到指定的DOM元素中。挂载完成后,会触发生命周期钩子mounted。vuejs会开启watcher来持续追踪依赖变化。 在已挂载的状态下,vuejs会持续追踪状态的变化,当状态发生改变时,watcher会通知虚拟DOM重新渲染视图,并在渲染视图之前触发beforeUpdate钩子函数,渲染完毕后,触发updated钩子函数。 (4)在卸载之前,会触发生命周期钩子beforeDestory。当实例上的$destory()方法被调用时,会卸载追踪依赖,子组件和事件监听器。卸载完成后会触发生命周期钩子destoryed

生命周期在真实场景下的应用 created:进行ajax请求异步数据的获取、初始化数据 mounted:挂载元素内dom节点的获取 nextTick:针对单一事件更新数据后立即操作dom updated:任何数据的更新,如果要做统一的业务逻辑处理 watch:监听具体数据变化,并做相应的处理 在这里插入图片描述

11、Vue父子组件生命周期钩子的执行顺序是什么

  • 在加载渲染阶段:子组件挂载完毕后,父组件才去mounted。执行钩子函数的顺序: 父beforecreate->父created->父beforemount->子beforecreate->子created->子beforemount->子mounted->父mounted
  • 子组件更新过程:父beforeupdate->子beforeupdate->子updated->父updated
  • 销毁过程:父beforedestory->子beforedestory->子destoryed->父destoryed

12、Computed与watch相关。在异步方面的区别是什么。

在这里插入图片描述

13、vue路由

路由就是通过不同的路径请求不同的资源; Vue的单页面应用是基于组件和路由的,路由用于设定访问路径,并将路由和组件映射起来。 前端路由的核心就是改变视图的同时不会向后端发起请求。 在这里插入图片描述

(1)Route、routes,router的区别

Route:单个路由或某一个路由 Routes:多个路由的集合,routes是一个数组 Router:路由器,相当于一个管理者。 举个例子:当用户在页面上点击按钮的时,router就会去routes中查找route。

14、前端路由相关:history和hash的区别;路由的两种模式,怎么体现hash值的变化

前端路由:改变视图的同时不会向后端发起请求。

Hash模式:hash指的是url尾巴后的#和后面的字符。hash虽然出现在URL中,但不会包含在HTTP请求中,对后端完全没有影响,因此改变hash不会重新加载页面。对于后端来讲,即使没有做到路由的全覆盖,也不会返回404错误。Vue-router会根据hash值的变化去访问对应的组件。

History模式:通过路径的变化去访问不同的组件,通过api改变路径而不向服务器发送请求实现。History模式利用了HTML5 history interface 中新增的pushState()和replaceState()方法。history不仅可以在url里面放参数,也可以将数据存在存在一个特定的对象中。 如果URL找不到资源,后端就把位置路径重定向到index.html

(1)History的优点

  • pushState() 通过 stateObject 参数可以添加任意类型的数据到记录中;而 hash 只可添加短字符串;
  • pushState() 设置的新 URL 可以是与当前 URL 同源(协议,域名,端口号都相同成为同源)的任意 URL;而 hash 只可修改 # 后面的部分,因此只能设置与当前 URL 同文档的 URL;
  • pushState() 设置的新 URL 可以与当前 URL 一模一样,这样也会把记录添加到栈中;而 hash 设置的新值必须与原来不一样才会触发动作将记录添加到栈中;

15、观察者模式和发布订阅者模式的区别,各自适用于什么场景

  • 观察者模式:定义了对象间一种一对多的关系,当一个对象的状态发生变化时,所有依赖它的对象都得到通知,并自动更新。观察者模式就是观察者和被观察者之间的通讯。
  • 发布订阅者模式:在发布者和订阅者之间存在第三个组件,称为消息代理或者调度中心。调度中心过滤所有发布者传入的消息并相应地分发给订阅者。发布者的消息不会直接传递给订阅者,也就是说,发布者和订阅者不知道彼此的存在。

最大的区别就是发布订阅者有一个事件调度中心。订阅者和发布者互不干扰,消除了依赖。实现了解耦,也可以实现更细粒度的控制。比如,发布者发布了很多消息,但是不想所有的订阅者都收到,就可以在调度中心做一些处理。 而观察者模式对所有订阅者一视同仁。

16、前端性能优化方式有哪些

(1)将多个小文件合并成一个大文件,减少HTTP请求。

因为一个完整的HTTP请求需要经历DNS查找,TCP握手,浏览器发出HTTP请求,服务器接收请求,服务器处理请求并响应,浏览器接收响应等过程。真正下载数据的时间占比很小,当传输的文件越大时,比例越高。

(2)使用CDN缓存静态资源。

CDN(内容分发网络)是一组分布在不同地理位置的web服务器。我们都知道,服务器离用户越远,延迟越高。CDN就是为了解决这个问题,在多个位置部署服务器,让用户离服务器更近,从而缩短请求时间。使用CDN不但可以加速网站访问,它的负载均衡分布式存储技术,还可以加强网站的可靠性。使用CDN还可以进行异地备援,当某个服务器发生意外故障时,系统会调用其他临近的健康服务器节点进行服务,可以提供100%的可靠性。 2.1如何实现负载均衡 使用了任播,对外任播组共用同一个ip,访问组内成员他会自动判断通信往返时延低的成员发送请求去处理,还会使用轮询的方式定期检查成员是否出现故障,出现故障就把成员从任播组中删除。 2.2CDN原理(用户访问部署了CDN的网站的过程) 在这里插入图片描述

(3)将CSS放在文件头部,JS放在文件底部

CSS执行会阻塞渲染,阻止JS执行。 JS加载和执行会阻塞HTML解析,阻止CSSOM树构建。 如果CSS和JS标签放在head标签中,他们需要加载和解析很久,所以页面就空白了。所以JS文件要放在底部。等HTML文件解析完了再加载JS文件,尽早向用户呈现页面的内容。 3.1为什么CSS会放在头部呢? 因为如果先加载HTML,再加载CSS,会让用户看到的是没有样式的页面,所以需要先加载CSS。 JS文件其实也可以放在头部,只要给script标签加上defer属性就可以了,让JS异步下载,延迟执行。

(4)使用字体图标iconfont代替图片图标

字体图标是矢量图,不会失真;生成的文件也小。

(5)减少重排重绘(因为重排重绘操作非常昂贵)

重排:根据生成的渲染树,得到节点的几何信息(位置,大小),这个过程称为重排。 重绘:根据生成的渲染树和重排得到的几何信息,得到节点的绝对像素的过程称为重绘。 重排一定引起重绘,而重绘不一定会引起重排 5.1 什么时候发生重排? 添加或删除可见的DOM元素 元素的位置发生变化 元素的尺寸发生变化(包括外边距、内边框、边框大小、高度和宽度等) 元素内容改变 页面一开始渲染的时候 浏览器的窗口尺寸变化(因为回流是根据视口的大小来计算元素的位置和大小的) 5.2 什么时候发生重绘? DOM元素的字体颜色,背景色,visibility等改变会发生重绘 5.3 如何减少重排重绘? 在css方面: 使用visibility代替display:none(因为visibility只引起重绘,display:none改变了布局,引起重排) 避免使用table布局 将动画效果应用到position属性为absolute或fixed的元素上(因为它们脱离了文档流),避免影响其他元素布局,这样只是重绘 在js方面: 最小化重排和重绘,可以合并多次对DOM和样式的修改,然后一次性处理掉(比如修改css的class属性) 避免频繁读取会引发重排重绘的属性(比如offsetTop,scrollTop等),如果要多次用,就用一个变量缓存起来

(6)使用事件委托

使用事件委托可以节省内存。事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。

(7)使用web workers

H5支持webworker,在js引擎下开了一个独立的线程,不会引起渲染线程的阻塞。

(8)图片懒加载(只用过Vue的插件vue-lazyload)

在页面中先不给图片设置路径,只有当图片出现在浏览器的可视区域时,才去加载真正的图片。对于图片很多的网站来说,一次性加载全部图片,会对用户体验造成很大的影响,所以需要使用图片懒加载。 8.1 懒加载实现 可以创建一个自定义属性data-src,用来存放图片的路径,当页面滚动到此图片出现在可视区域时,用JS取到该图片的data-src的值赋给src。 8.2 如何判断一个元素出现在视野中? 元素相对顶点的距离(文字) <= 窗口高度 + 滚动的距离

17、MVVM开发模式与MVC的区别

(1)MVC

  • MVC模式包括view视图层,model数据层,controller控制层。各部分之间的通信是单向的。view传送指令到controller,controller完成业务逻辑(手动编写大量DOM操作)之后,要求model改变状态,model将新的数据发送到view,用户得到反馈。 在这里插入图片描述

(2)MVVM

  • MVVM是Model-view-viewmodel的简写。包括model数据层,view视图层,viewmodel层。 View和model是不能直接通信的,只能通过viewmodel进行交互,viewmodel能够监听到数据的变化,然后通知视图进行自动更新;而当用户操作视图时,viewmodel也能监听到视图的变化,然后通知数据做相应的改动。各部分的通信是双向的。采用双向数据绑定。 在这里插入图片描述

(3)MVC和MVVM的区别:

MVVM通过数据来显示视图层;MVC是通过DOM操作来显示视图层。 MVC中的controller演变成了MVVM中的viewmodel。

18、Vue有哪些指令

V-if:判断是否隐藏 V-on(缩写为@):绑定事件 V-show:判断元素是否隐藏 V-for:循环遍历数据 V-else V-model:实现双向绑定 V-bind(缩写为:):动态绑定属性

19、v-if和v-show有什么区别

V-if是根据判断条件动态的渲染标签,增删DOM元素; V-show是根据判断条件动态的显示和隐藏元素。频繁的DOM操作会影响页面的加载速度和性能,因此v-show的性能比v-if好。

20、21.介绍一下webpack和node.js

(1)Webpack:

webpack是一个模块打包器,webpack把html,css,js,图片等文件看作是一种资源,每个资源文件都是一个模块文件,webpack就是根据每个模块文件之间的依赖关系将所有的模块打包起来。 它的核心就分为入口(entry),加载器(loader),插件(plugins),出口(output) Entry:告诉webpack从哪里开始打包文件内容 Loader:webpack只能处理js模块,如果要处理其他类型的文件,就要用loader进行转换。(就比如添加了css模块,就需要用到style-loader和css-loader,是从右向左读的,css-loader加载css文件,style-loader负责将样式添加到DOM里) Plugins:loader只能用于某些类型的模块,plugin的功能更强大;plugin可以对loader打包后的文件进行二次优化,比如代码压缩从而减小文件体积。 Output:告诉webpack在哪里输出它创建的bundle

(2)Node.js:

是一个基于Chrome V8引擎的JavaScript运行环境

(3)vue文件是怎么解析的?vue-loader做了什么

21、 vue组件封装,写逻辑部分。购物车全选单选。(手写vue全选反选框组件)

先写data,再写template部分,最后绑定事件,再写事件

<template>
  <div>
    <span>全选:</span>
    <!-- 2.v-model 关联全选按钮的 选中 状态 -->
    <input type="checkbox" v-model="isAll" />
    <!-- 5.给 反选 按钮绑定点击事件 -->
    <button @click="reBtn">反选</button>
    <ul>
      <li v-for="(obj, index) in arr"
          :key="index">
        <!-- 1.让对象的 c 属性,关联 选中 状态 -->
        <input type="checkbox"
               v-model="obj.c" />
        <span>{{obj.name}}</span>
      </li>
    </ul>
  </div>
</template>
 
<script>
export default {
  data () {
    return {
      arr: [
        {
          name: "猪八戒",
          c: false,
        },
        {
          name: "孙悟空",
          c: false,
        },
        {
          name: "唐僧",
          c: false,
        },
        {
          name: "白龙马",
          c: false,
        },
      ],
    };
  },
  // 计算属性 isAll
  computed: {
    // isAll(){
    // // 3. 统计小选框状态 -> 全选状态
    // // every() 查找数组里“不符合”条件的数据,直接原地返回 false
    // return this.arr.every(obj => obj.c === true)
    // },
    // isAll改成完整写法, set里获取到全选框, 勾选的状态值
    isAll: {
      set (val) {
        // 4.拿到全选框的选中状态(true/false),从而影响小选框的选中状态
        this.arr.forEach(obj => obj.c = val)
      },
      get () {
        // 3. 统计小选框状态 -> 全选状态
        // every() 查找数组里“不符合”条件的数据,直接原地返回 false
        return this.arr.every(obj => obj.c === true)
      }
    },
  },
  methods: {
    reBtn(){
      // 6.点击的时候让对象里的 c 属性取反再赋予回去
      this.arr.forEach(obj => obj.c = !obj.c)
    }
  },
};
</script>

22、vue的data为什么是函数 具体原因(构造函数的原型对象有关)

组件中的data必须是一个函数,然后return一个对象;new Vue实例里面,data可以直接是一个对象。

data是挂载到原型对象上的,所有的实例都共用原型对象下的方法或值。组件是用来复用的,而一个组件不管复用过多少次,组件中的data数据都应该是隔离的,互不影响的。我们想让每个组件实例都有自己的作用域,每个实例相互独立不会相互影响,所以把data变成了一个函数。每次调用data函数的时候都会return一个新的对象,他们的内存地址都是不一样的,这样就不会相互影响。

23、vue组件渲染的原理(vue的模板编译)

在这里插入图片描述

在这里插入图片描述

(1)解析器(比如babel)(将模板解析成AST)

原理:在解析器内部,分成了很多小解析器,包括过滤器解析器,文本解析器,HTML解析器。然后通过一条主线将这些解析器组装在一起。 在这里插入图片描述

AST(抽象语法树Abstract syntax tree): 只是用JS中的对象来表示节点树,对象中的属性用来保存节点所需的各种数据,和vnode很像。

{
Tag:’div’,
Type:1,
Parent:undefined,
Children:[
{
Tag:’p’,
Type:1,
}
]
}

文本解析器:解析带变量的文本({{}}),不带变量的文本不需要使用文本解析器来解析 HTML解析器:解析模板 HTML解析器内部原理:一小段一小段地截取模板字符串,每截取一小段字符串,就会根据截取出来的字符串类型 触发不同的钩子函数(包括开始标签钩子函数start(),结束标签钩子函数end(),文本钩子函数chars(),注释钩子函数comment()),在不同的钩子函数中构建AST节点,直到模板字符串截空停止运行。 html解析器是从左到右解析的(但是没有层级结构),需要结合栈(具有层级结构)。 构建AST层级关系:每次触发start函数,入栈;每次触发end函数,从栈中弹出一个节点。栈的最后一个节点为正在构建节点的父节点

(2)优化器(遍历AST,标记静态节点)

好处:每次重新渲染时,不需要为静态子树创建新节点;在虚拟DOM中更新的过程可以跳过 优化器原理:当模板被解析器解析出AST时,会根据不同元素类型设置不同的type值,type为2,是带变量的动态文本节点,不是静态节点;type为3,是纯文本节点,是静态节点;type为1,是元素节点,有可能是静态节点,也有可能不是静态节点。

(3)代码生成器(将AST生成代码字符串,代码字符串会被放到渲染函数中使用)

原理:代码生成器其实就是字符串拼接的过程,通过递归AST生成字符串。最先生成根节点,然后在子节点字符串生成后,将其拼接在根节点的参数中,子节点的子节点拼接在子节点的参数中。这样一层一层的拼接,直到最后拼接成完整的字符串。节点有元素节点,文本节点,注释节点,不同类型节点的生成方式不一样。

24、手写发布订阅者

 class Subject {
      observers = []//记录观察者
      addObserver(observer) {//添加观察者
        this.observers.push(observer)
      }
      removeObserver(observer) {//删除观察者
        let index = this.observers.indexOf(observer)
        if (index > -1) {
          this.observers.splice(index, 1)
        }
      }
      notify() {//通知观察者更新
        this.observers.forEach(observer => {
          //notify 时实际上调用全部观察者 observer 自身的 update 方法
          observer.update()
        })
      }
    }
    class Observer {//观察者类
      update() { }//可以订阅主题,把自己加入到主题的订阅者列表里
      subscribeTo(subject) {
        subject.addObserver(this)//把自己加入到主题的订阅者列表里
      }
    }
    let subject = new Subject()
    let observer = new Observer()
    observer.update = function () {
      console.log('observer update')
    }
    observer.subscribeTo(subject)  //观察者订阅主题

    subject.notify()

26、登录校验

token

令牌,token是服务器发的唯一标识符,需要把token在请求拦截时加上。

页面刷新之后,token还存在吗

切换页面或者刷新页面时,vuex中保存的token就丢失了。因为vuex存储数据不是持久化,一刷新数据就没有了。所以要把token存到本地localstorage中,state先判断本地存储里面有没有,有的话获取,没有的话就是还没有登录,重定向到登录页面。

为什么不把token存到cookie中,cookie和localstorage哪个安全?

27、手写事件总线

class EventBus {
				constructor() {
					this.events = {}//存放事件
				}
				on(eventName, cb) {//On用来接收事件
					if(cb) this.events[eventName] = cb
					else this.events[eventName] = null
				}
				emit(eventName, arg) {//emit用来发送事件
					if(this.events[eventName]) {
						return this.events[eventName](arg)
					}
				}
			}

			let bus = new EventBus()
			bus.on('event', arg => console.log('event', arg))
			bus.emit('event', 123) // event 123
			bus.on('handle', arg => console.log('handle', arg))
			bus.emit('handle', 'hello world')  // handle hello world
			console.log(bus);

计网部分

1、浏览器请求网页的过程;浏览器解析并渲染页面的过程(输入一个URL的过程)

(1)输入域名 (2)进行DNS解析,将域名解析成对应的IP地址 (2)客户端和服务器端建立TCP链接(三次握手) (3)浏览器向服务器发送HTTP请求 (4)服务器进行HTTP响应 (5)浏览器解析渲染页面 (6)关闭TCP链接(四次挥手)

(1)DNS解析过程:(本地DNS->根DNS->顶级DNS->权威DNS)

在浏览器上输入域名(比如:www.163.com)之后,主机会发送一个DNS请求到本地DNS服务器。 本地DNS服务器会先查询它的缓存记录,如果有域名和对应的IP地址,就直接返回给主机(此过程是递归方式进行查询)。 如果没有,本地DNS服务器会向根DNS服务器查询。 根DNS服务器没有记录具体的域名和IP地址的对应关系,而是告诉本地服务器,你可以到哪个顶级DNS服务器查询,并给出顶级DNS服务器的IP地址(这种过程是迭代的过程)。本地DNS服务器会向对应的顶级DNS服务器(.com顶级DNS服务器)发送请求。 (com)顶级DNS服务器收到请求之后,也不会直接返回域名和IP地址的对应关系,而是告诉本地DNS服务器对应的权威DNS服务器(dns.163.com)的IP地址。 本地DNS服务器向对应的权威DNS服务器发送请求,这时就能收到域名和IP地址的对应关系了。 本地DNS服务器会把IP地址给主机,也会把对应关系缓存下来。

(2)TCP三次握手

三次握手过程

TCP采用三次握手建立连接。 第一次握手:客户端向服务器端发送序号为x的SYN报文段,代表连接请求并给出客户端选择的起始序号为x。TCP规定,SYN报文段不能携带数据,但要消耗掉一个序号。这时,TCP客户端进入SYN-SENT(同步已发送)状态。 第二次握手:服务器端接收SYN报文段并同意建立连接,服务器端向客户端发送序号为y,确认序号为x+1的SYNACK报文段,这个报文段也不能携带数据,也要消耗掉一个序号。这时,服务器端会分配缓存和变量并且进入SYN-RCVD(同步收到)状态。 第三次握手:客户端接收SYNACK报文段之后,再次确定建立连接,发送序号为x+1,确认序号为y+1的ACK报文段。这个报文段可以携带数据,客户端会分配缓存和变量并且进入ESTABLISHED(已建立连接)状态。

为什么是三次握手,而不是两次或者四次握手呢?

不可以两次握手的原因: 举个例子:比如A向B发出了连接请求,A的连接请求报文段在网络结点长时间滞留了,导致连接释放以后的某个时间段才到达了B。本来这是一个早已失效的报文段,但是B收到这个失效的请求报文之后,就误认为是A发出的一次新的连接请求,于是就向A发出确认报文段,同意建立连接。 对于这种情况,如果不进行第三次握手,B发出确认之后就认为新的运输连接已经建立了,并一直等待A发来数据。B的许多资源就这样白白浪费了。 如果采用了三次握手,由于A实际上并没有发出连接建立请求,所以不会理会B的确认,也不会向B发送数据。B由于收不到确认,就知道A并没有要求建立连接。 不需要四次握手的原因: 完全可靠的通信协议是不存在的。在经过三次握手之后,客户端和服务器端已经可以确认之前的通信状况,都收到了确认信息。所以再增加握手次数也不能保证后面的通信完全可靠,所以是没有必要的。

三次握手哪次最容易被攻击

第二次握手最容易被攻击。TCP协议容易受到SYN洪泛攻击。攻击者向服务器发送大量的TCP SYN报文段,而不完成三次握手的第三步,服务器不断为这些半开连接分配资源,导致服务器的连接资源消耗殆尽。

(3)TCP四次挥手

四次挥手过程

数据传输结束后,通信的双方都可以释放连接。比如有两个主机A和B,现在他们都处于ESTABLISHED状态。

第一次挥手:主机A向主机B发送序号为x的FIN报文段,表示请求释放连接,并停止发送数据,主动关闭TCP连接。这时A进入FIN-WAIT1(终止等待1)状态,等待B的确认。FIN报文段不携带数据,但要消耗一个序号。

第二次挥手:主机B收到连接释放报文段之后,立即向A发送序号为y,确认序号为x+1的ACK报文段。这时B进入CLOSE_WAIT(关闭等待)状态。这个时候TCP连接处于半关闭状态,也就是A不能发送数据了,但是B仍然可以发送数据。主机A收到来自B的确认之后,就进入FIN_WAIT2(终止等待2)状态,等待B发出的释放连接报文段。

第三次挥手:主机B如果没有要发送的数据,就会向A发送序号为y,确认序号为x+1的FINACK报文段。这时B进入了LAST_ACK(最后确认)状态,等待A的确认。

第四次挥手:A在收到B的连接释放报文后,就会向B发送序号为x+1,确认序号为y+1的ACK报文段确认。然后A会进入TIME-WAIT(时间等待)状态。必须经过2MSL(最长报文段寿命)之后,A才能进入到CLOSE状态,结束这次TCP连接。B如果一收到确认就进入CLOSED状态。在释放连接之前,B结束TCP连接时间要早于A。

为什么A在TIME-WAIT状态必须等待2MSL的时间呢?

MSL:最大报文段生存时间 为了保证A发送的最后一个ACK报文段能够到达B。 防止已经失效的连接请求报文段出现在本连接中。

2msl后,客户端怎么知道服务器端收到确认了

为什么第二次和第三次不能合并,第二次和第三次之间等待的是什么?

当服务器执行第二次挥手后,此时证明客户端不能再向服务器发送任何数据,但是服务器端可能还正在给客户端发送数据。服务端会等待把之前未传输完的数据传输完毕后再发送关闭请求。 在这里插入图片描述

TCP四次挥手为什么双方都可以释放连接

(4)浏览器解析渲染页面(浏览器的渲染原理)

在这里插入图片描述

2、重排重绘;怎么减少

重排:根据生成的渲染树,得到节点的几何信息(位置,大小),这个过程称为重排。 重绘:根据生成的渲染树和重排得到的几何信息,得到节点的绝对像素的过程称为重绘。 重排一定引起重绘,而重绘不一定会引起重排

(1)什么时候发生重排?

添加或删除可见的DOM元素 元素的位置发生变化 元素的尺寸发生变化(包括外边距、内边框、边框大小、高度和宽度等) 元素内容改变 页面一开始渲染的时候 浏览器的窗口尺寸变化(因为重排是根据视口的大小来计算元素的位置和大小的)

(2)什么时候发生重绘?

DOM元素的字体颜色,背景色,visibility等改变会发生重绘

(3)如何减少重排重绘?

在css方面: 使用visibility代替display:none(因为visibility只引起重绘,display:none改变了布局,引起重排) 避免使用table布局 将动画效果应用到position属性为absolute或fixed的元素上(因为它们脱离了文档流),避免影响其他元素布局,这样只是重绘 在js方面: 最小化重排和重绘,可以合并多次对DOM和样式的修改,然后一次性处理掉(比如修改css的class属性) 避免频繁读取会引发重排重绘的属性(比如offsetTop,scrollTop等),如果要多次用,就用一个变量缓存起来

(4)浏览器的优化机制

由于每次重排都会造成额外的计算消耗,因此大多数浏览器都会通过队列化修改并批量执行来优化重排过程。 浏览器会将修改操作放入到队列里,直到过了一段时间或者操作达到了一个阈值,才清空队列。但是,当你获取布局信息的操作的时候,会强制队列刷新。比如当你使用了:offsetTop,offsetLeft,offsetWidth,offsetHeight,scrollTop,scrollLeft,clientTop,clientLeft等这些属性时会强制队列刷新,所以要避免使用,若要使用,最好用变量存储起来。

3、TCP协议如何保证可靠传输?

(1)数据包校验(TCP使用了校验和方法,TCP报文段有一个伪首部用来计算校验和,不传递):检验数据在传输过程中的变化,若校验出包有差错,就丢弃报文段并不给出响应,这时TCP发送数据端超时后会重发数据。 (2)应答机制:当tcp收到发自TCP连接另一端的数据,它会发送一个确认。 (3)超时重发:当发送端发出一个报文段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,就重发这个报文段。 (4)对失序数据包重排序:TCP报文作为IP数据报来传输,而IP数据报的到达可能会失序,因此TCP报文段的到达也可能会失序。TCP对失序数据重新排序,然后才交给应用层。 (5)丢弃重复数据 (6)流量控制(滑动窗口协议):TCP连接的每一方都有固定大小的缓冲空间。TCP接收端只允许另一端发送接收端缓冲区所能容纳的数据,TCP发送端使用可变的滑动窗口来调节发送速率,不使接收端缓存溢出。 (7)拥塞控制:拥塞控制是TCP发送方针对网络拥堵情况所采取的措施。TCP发送方可以通过是否丢包(超时;收到3个连续的重复ACK)感知到拥塞,发送方使用拥塞窗口cwnd控制发送速率,当确认拥塞后,采用慢启动SS算法和加性增乘性减AIMD算法来调整发送速率。 当cwnd<门限值的时候,使用慢启动算法,以指数方式增长发送速率,直到接近门限值;当cwnd>=门限值时,表示网络可能进入拥塞状态,发送速率会降为以线性增长,进入CA拥塞避免阶段。乘性减是指发现丢包事件后,TCP要采取措施来迅速减小拥塞窗口。当超时事件发生时,TCP发送方会把窗口减到最小,即一个MSS(最大段长度),同时把门限值设置为之前的1/2,最后进入慢启动阶段。如果TCP发送方收到3个冗余ACK时,会把门限值减半,并把cwnd设置为门限值,并且进入AIMD阶段。

4.讲一下token(概念)

Token的意思是令牌,是服务端生成的一串字符串,作为客户端进行请求的一个标识。是一种服务端无状态的认证方式。最简单的token信息:uid(用户的唯一标识符),time(当前事件的时间戳),sign(签名,由token的前几位和哈希算法压缩为一定长的十六进制字符串)。

5、讲一下cookie和session;如果要做一个登录效果,cookie和session是怎么交互的

cookie和session都是客户端与服务器之间保持状态的解决方案。Cookie机制是在客户端保持状态的方案,session机制则是在服务器端保持状态的方案。

cookie

Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就会返回一个包含set-cookie首部的http响应报文,而客户端浏览器会把cookie保存起来。当浏览器再请求该网站时,浏览器会把请求的网址和cookie一同提交给服务器,服务器检查该cookie,以此来辨认用户状态。服务器还可以根据需要修改cookie的内容。

cookie的secure属性是干什么的

安全性指定Cookie是否只能通过https协议访问,一般的Cookie使用HTTP协议即可访问,如果设置了Secure(没有值),则只有当使用https协议连接时cookie才可以被页面访问。

cookie的httpOnly是干什么的

如果在Cookie中设置了"HttpOnly"属性,那么通过程序(JS脚本、Applet等)将无法读取到Cookie信息,这样能有效的防止XSS攻击

Session

客户端请求服务器,如果服务器记录该用户状态,就获取session来保存状态,这时,如果服务器已经为此创建过session,服务器就按照sessionid把这个session检索出来使用;如果客户端请求不包含sessionid,则为此客户端创建一个session并且生成一个与此session相关的sessionid,并将这个sessionid在本次响应中返回给客户端保存。保存这个sessionid的方式可以采用cookie机制,这样在交互过程中浏览器可以自动的把这个标识发给服务器;如果浏览器禁用cookie的话,可以通过URL重写机制将sessionid传回服务器。

Session存放的几种方案

(1)存放在内存中,用sessionid来标识用户,这样的session十分依赖cookie。如果浏览器禁用了cookie,session就没有用武之地了。也可以把sessionid存在数据库里,缺点是数据库访问压力大。 (2)将session内容存放在cookie中 (3)使用用户的一部分字段信息加密得到一串字符串token返回给用户。用户提交请求时必须带上token。不需要存储token,只要在想得到用户信息时解密token就行。

Session和cookie的区别

(1)实现机制:session的实现经常依赖于cookie机制,通过cookie机制回传sessionid。 (2)大小限制:cookie有大小限制,浏览器对每个站点也有cookie个数的限制;session没有大小限制。 (3)安全性:cookie存在安全隐患,通过拦截或者本地文件找到cookie后可以进行攻击;而session保存在服务器端,相对更加安全。 (4)服务器资源消耗:session保存在服务器一段时间后才会消失,如果session过多会增加服务器的压力。

6、TCP和UDP

(1) 区别

TCP是面向连接,可靠的传输服务。TCP面向字节流传输。TCP要求通信数据可靠,一般用于文件传输,发送接收邮件,远程登录等场景。 UDP是无连接,不可靠的传输服务。UDP面向数据报文段传输。UDP要求通信速度高。一般用于即时通信,比如QQ语音,视频,直播等。

(2)对应的应用层协议

TCP:FTP(文件传输协议),Telnet(远程登录协议),SMTP(简单邮件传送协议),POP3(取邮件),HTTP UDP:DNS,SNMP(网络管理协议),TFTP(简单文件传输协议)

7、TCP粘包/拆包

(1) 什么是粘包、拆包

如果客户端连续不断的向服务器端发送数据包时,服务端接收的数据会出现两个数据包黏在一起的情况。 一个数据包中包含了发送端发送的两个数据包的信息,这种现象就称为粘包

(2)如何解决粘包、拆包

在包头首部加上数据包的长度(UDP没有粘包问题,但是有丢包和失序问题 )

8、常见的http请求方法有哪些?

Get:获取资源 Post:传输实体主体 Put:上传文件 Delete:删除文件 OPTION:预检请求,获取服务器所支持的通信选项(请求方式) Patch:对资源进行部分修改 Connect:要求与代理服务器通信时建立隧道。使用SSL(安全套阶层)和TLS(传输层安全)协议把通信内容加密后经网络隧道传输。 Trace:追踪路径。

9、get和post的区别;get和post的安全性(post高)

  • 本质区别:get只是一次http请求,post先发送请求头在发送请求体,实际上是两次请求。
  • 功能上讲,get一般用于从服务器上获取资源,post一般用来更新服务器上的资源。
  • 请求参数上讲,get请求的数据会附在URL之后,也就是将数据放置在HTTP报文的请求头中,用?分割url和传输数据,参数之间以&相连。而post请求会把提交的数据放置在http请求的报文请求体中。
  • 安全性而言,post的安全性比get安全性高。因为get请求提交的数据将明文出现在了url上,而Post请求参数则被包装在请求体中,相对安全。
  • 请求的大小来看,get请求的长度受限于浏览器/服务器对URL长度的限制,允许发送的数据量较小,而post请求是没有限制大小的。

10、HTTP和HTTPS

(1)HTTP和HTTPS的概念

http(超文本传输协议):用来在浏览器和web服务器之间传送超文本的协议。 https:是由HTTP加上TSL/SSL协议构建的可进行加密传输,身份认证的网络协议。 TSL:传输层安全性协议 SSL:安全套阶层

(2)HTTP和HTTPS的区别

(1)资源开销:HTTP是超文本传输协议,信息是明文传输;HTTPS则是具有安全性的ssl加密传输协议,需要消耗更多的cpu和资源 (2)端口不同:HTTP协议默认的端口为80,HTTPS是443 (3)安全性:HTTP连接很简单,是无状态的;HTTPS协议是由TSL+HTTP协议构建的可进行加密传输,身份认证的网络协议,比HTTP协议安全。

(3)HTTPS的优缺点

优点: (1)使用HTTPS可以认证用户和服务器,确保数据发送到正确的客户机和服务器 (2)HTTPS协议比HTTP协议安全,可防止数据在传输过程中不被窃取,改变,确保数据的完整性。 缺点: (1)HTTPS协议握手阶段比较费时,会使页面的加载时间延长50%,增加10%到20%的耗电。 (2)HTTPS会影响缓存,增加数据开销和功耗。 (3)SSL证书需要绑定IP,不能在同一个IP上绑定多个域名

(4)HTTP请求头,响应头

HTTP请求头

Accpet:告诉服务端,客户端接收什么类型的响应 ● Referer:表示这是请求是从哪个URL进来的,比如想在网上购物,但是不知道选择哪家电商平台,你就去问度娘,说哪家电商的东西便宜啊,然后一堆东西弹出在你面前,第一给就是某宝,当你从这里进入某宝的时候,这个请求报文的Referer就是www.baidu.com ● Cache-Control: 对缓存进行控制 ● Host:指定要请求的资源所在的主机和端口 ● User-Agent 作用:告诉服务器,客户端使用的操作系统、浏览器版本和名称

HTTP响应头

Last-Modified:WEB 服务器认为对象的最后修改时间,比如文件的最后修改时间,动态页面的最后产生时间等等 Content-Language:WEB 服务器告诉浏览器自己响应的对象的语言。

(5)请求头中的Keep-alive

HTTP协议采用“请求-应答”模式,当使用普通模式,即非KeepAlive模式时,每个请求/应答客户和服务器都要新建一个连接,完成 之后立即断开连接(HTTP协议为无连接的协议);当使用Keep-Alive模式(又称持久连接、连接重用)时,Keep-Alive功能使客户端到服 务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive功能避免了建立或者重新建立连接。 http keep-alive:   在一次tcp连接中可以连续发送多次数据,即可以保持一段时间的tcp连接,在这个保持的通道上有多个request、多个response。而不用每发一次数据就要重新进行三次握手连接,发完一次数据就要立即进行四次挥手释放连接。 这样可以提高性能和吞吐率。

11、http常见的状态码有哪些

100:continue,表示到目前为止都很正常,客户端可以继续发送请求

200:ok 表示请求成功 204:no content,请求成功,但是返回的响应报文中不包含实体的主体部分

301:永久性重定向;代表URL永久性转移 302:临时性重定向;代表URL暂时性转移 303:和302功能相同(临时性重定向),但是303明确要求客户端采用get方法获取资源 304 Not Modified:说明无需再次传输请求的内容,也就是说可以使用缓存的内容

400:请求报文中存在语法错误 401 :未经许可,需要通过HTTP认证; 403 Forbidden:服务器拒绝该次访问(访问权限出现问题) 404:not found表示服务器上无法找到请求的资源

500:服务器正在执行请求时发生错误 501:请求的方法不被服务器支持,因此无法被处理

12、http1.0、http1.1、http2.0、http3.0

(1)HTTP1.1相对于HTTP1.0的主要变化

(1)连接方面的区别: 1.0默认支持的是短连接,也就是一次http请求需要建立一次TCP连接,请求完之后,连接就会断开。 1.1默认采用长连接(keep-alive),多个http请求可以经过同一个TCP连接传送。 (2)HTTP1.1支持只发送header而不发送body。原因是先用header判断能否成功,再发送数据,节约带宽,事实上,post请求默认就是这样做的。 (3)http1.0只支持head,get,post请求方式;http1.1新增了delete,put等。

(2)HTTP1.1的缺陷

(1)高延迟-带来页面加载速度的降低 网络延迟主要由于队头阻塞,导致带宽无法被利用。队头阻塞是指当发送的请求序列中的一个请求因为某种原因阻塞时,在后面的请求也一并被阻塞,会导致客户端迟迟收不到数据。 针对队头阻塞,人们尝试了几种方法: 合并小文件减少资源数(比如精灵图)。 将同一页面的资源分散到不同域名下,提升连接上限。chrome有个机制,对于同一个域名,默认允许同时建立6个TCP持久连接。 (2)无状态特性-带来了巨大的http头部 http是无状态协议,对于连接状态没有记忆能力,每一个连接都是新的连接。所以报文header会携带许多固定的头字段,多达几百字节,而body却经常只有几十字节。Header里携带的内容过大,在一定程度上增加了传输的成本。 (3)明文传输,不安全 (4)不支持服务端推送

(3)HTTP2.0相对于HTTP1.0的主要变化

(1)http2.0采用二进制传输数据,而http1.x是纯文本形式的报文,二进制协议解析起来更高效。 (2)http2.0压缩了请求头,数据占用空间更少。使用HPACK算法,在客户端和服务器端建立字典,用索引号表示重复的字符串,还采用哈夫曼编码来压缩整数和字符串。 (3)http2.0支持多路复用。同一个tcp连接可以并发处理多个请求,方法是把http数据包拆为多个帧,并发有序的发送,根据序号在另一端重组,而不需要一个个http请求顺序到达。 (4)http2.0支持服务端推送 (5)http2.0适用于https场景。因为在http和tcp中间加了一层ssl层。

有了gzip压缩,为什么http2.0对header还需要进行压缩,为什么gzip不作用于header

gzip是压缩body部分的。

HTTP压缩的过程:

  1. 浏览器发送Http request 给Web服务器, request 中有Accept-Encoding: gzip。 (告诉服务器, 浏览器支持gzip压缩)
  2. Web服务器接到request后, 生成原始的Response, 其中有原始的Content-Type和Content-Length。
  3. Web服务器通过Gzip,来对Response进行编码, 编码后header中有Content-Type和Content-Length(压缩后的大小), 并且增加了Content-Encoding:gzip. 然后把Response发送给浏览器。
  4. 浏览器接到Response后,根据Content-Encoding:gzip来对Response 进行解码。 获取到原始response后, 然后显示出网页。

HTTP压缩的好处、不足:

1)http压缩对纯文本可以压缩至原内容的40%, 从而节省了60%的数据传输。

2)JPEG这类文件用gzip压缩的不够好。

3)简单来说, Gzip压缩是在一个文本文件中找出类似的字符串, 并临时替换他们,使整个文件变小。这种形式的压缩对Web来说非常适合, 因为HTML和CSS文件通常包含大量的重复的字符串,例如空格,标签。

(4)HTTP2.X的缺陷

(1)TCP和TLS建立连接的时延长,在传输数据之前,需要花掉3-4个RTT(往返时延)。 (2)队头阻塞没有彻底解决。HTTP2中,多个请求是跑在一个TCP管道中的,但出现丢包的时候,整个TCP都要开始等待重传。那么就会阻塞该TCP链接中的所有请求。 (3)多路复用导致服务器压力上升 (4)多路复用容易超时

(5)HTTP3.0相对于HTTP2.X的变化

(1)HTTP3.0修改了底层的支撑协议,另起炉灶搞了一个基于UDP的QUIC协议,让HTTP跑在QUIC上而不是TCP上。QUIC协议基于UDP,而UDP又是无连接的,根本不需要握手和挥手,所以就比TCP快。又取了TCP的精华,提供了数据包重传,拥塞控制等一些特性,保证了数据可靠性传输。实现了既可靠又快的协议。 (2)QUIC协议实现了在同一物理连接上可以有多个独立的逻辑数据流。实现了数据流的单独传输,解决了TCP中队头阻塞的问题。

13、HTTPS的连接过程

在这里插入图片描述

https传输信息的时候使用对称加密 握手的时候使用非对称加密算法,用来加密握手之后的请求和应答 数字签名(hash算法)保证数据的完整性 SSL:安全套接层 TLS:传输层安全性协议

(1)对称加密和非对称加密

(1)对称加密:加密和解密使用同一个密钥 优点:计算量小、加密和解密速度比较快 缺点:密钥容易泄露,在传输加密数据之前需要传递密钥,一个用户对应一个密钥,服务端管理密钥麻烦。

(2)非对称加密:使用一对非对称密钥,即公钥和私钥。使用公钥加密,私钥解密。 优点:数据传输安全 缺点:计算量大、加密解密的速度慢

(2)数字签名

为了防止数据在传输过程中被替换,让发送端做一个数字签名,使用私钥生成签名,公钥来解签,每个人都可以解签,查看消息的归属人。

(3)证书(公钥证书)

对称加密中,双方使用公钥解密,虽然数字签名可以保证数据不被替换,但是数据是由公钥加密的,如果公钥也被替换,仍然可以伪造数据。因为用户不知道对方提供的公钥是假的。 为了保证发送方的公钥是真的,CA会颁发一个证书。里面保存着归属者的基本信息,证书过期时间,归属者的公钥,并由CA(认证机构)施加数字签名,表明认证机构认定该公钥的确属于此人。

14、http缓存类型/浏览器和服务端交互缓存/浏览器的缓存机制,实现方式

http缓存类型(浏览器缓存)分为强制缓存协商缓存。 当浏览器向服务器发起请求时,服务器会将缓存规则放入HTTP响应报文的HTTP头中,和请求结果一起返回给浏览器。

(1)强制缓存

**向浏览器缓存查找该请求的结果,并根据该结果的缓存规则来决定是否使用该缓存结果。**控制强制缓存的字段分别是expires和catch-control,catch-control的优先级比expires高。Expires是HTTP/1.0控制网页缓存的字段,它存的是缓存的到期时间,也就是说再次发起该请求时,如果客户端的时间小于expires的值,直接使用缓存结果。在HTTP/1.1中,使用的是catch-control字段控制网页缓存。 在这里插入图片描述 强制缓存情况主要有三种,(1)不存在缓存结果和缓存标识,强制缓存失效,直接向服务器发送请求。(2)存在该缓存结果和缓存标识,但结果失效了,强制缓存失效,使用协商缓存。(3)存在缓存结果和缓存标识,结果未失效,强制缓存生效,直接返回结果。

- 浏览器缓存存放在哪里

浏览器的缓存放在内存硬盘中, 内存缓存具有快速读取和时效性的特点,也就是说内存缓存会将编译后的文件,直接存入该进程的内存中,占据进程一定的内存资源,方便下次运行时快速读取。一旦进程关闭,该进程的内存就会清空。 硬盘缓存则是直接将缓存写入硬盘文件,读取速度比内存慢很多。浏览器会将JS和图片等文件解析执行后直接存入内存缓存中,当刷新页面时只需要从内存缓存中读取。而css文件会存入硬盘文件中,每次渲染页面都会从硬盘读取缓存。

(2)协商缓存

强缓存失效后,浏览器携带缓存标识向服务器发送请求,如果该资源更新了,就重新返回请求结果,状态码为200;如果资源没更新,就返回304,继续使用缓存文件。 在这里插入图片描述

15、计算机网络五层模型

教学:物理层-》数据链路层-》网络层-》传输层-》应用层 OSI模型:物理层-》数据链路层-》网络层-》传输层-》会话层-》表示层-》应用层 TCP/IP模型:网络接口层-》网络层-》传输层-》应用层