一.浏览器
1.重排和重绘
概念
重排:当DOM的变化影响了元素的几何信息(大小或者位置),浏览器需要重新计算元素的几何属性,将其安放在页面的正确位置,浏览器的这一行为称之为重排,也叫回流。
重绘:当一个元素的外观发生改变,但是其在页面中的位置没有变化,浏览器重新绘制出该元素的过程叫做重绘。
常见的触发方式:
重排
- 改变元素的大小,位置,内容等
- 新增或者删除元素
- 改变浏览器窗口大小
- 修改元素的CSS伪类
- 查询元素某些属性比如offsetWidth,offsetHeight等
重绘
- 改变元素的颜色,背景,装饰线等
如何减少重排次数来优化浏览器渲染的性能
- 分离读写操作
- 样式集中改变
- DOM离线操作(display:none)
- 使用absolute或者fixed脱离文档流
2.EventLoop
概念
JavaScript是单线程的,有一个执行栈,按顺序入栈出栈执行同步操作,遇到异步操作,不会等待执行结果,而是将异步操作挂起,将结果按顺序放入执行队列,当执行栈中没有内容的时候,才会将执行队列里的返回结果按顺序取出,进行回调操作
宏任务与微任务
- 执行一个宏任务(栈中没有就从事件队列中获取,主线程也是宏任务)
- 执行过程中如果遇到微任务,就将它添加到微任务的任务队列中,遇到宏任务,就添加到宏任务队列
- 当前宏任务执行完毕后,立即执行当前微任务队列中的所有微任务(依次执行)
- 微任务队列为空后,开始下一个宏任务(从宏任务队列中获取)
二.html
1.事件冒泡,事件捕获,事件委托
事件冒泡
触发了子元素绑定的事件后,寻找其父元素是否有定义该事件,有的话也会触发,并且再次往外寻找父元素直到body
事件捕获(一般不会用到)
和事件冒泡相反,先从最外层开始寻找是否有该事件,一直往里面找到绑定了该事件的子元素
事件委托
利用事件冒泡实现的一种机制,在父元素上绑定事件,通过事件冒泡,可以让所有子元素绑定同一事件,任何一个子元素都能触发该事件,并且父元素新增子元素后,该新增的子元素也能触发。常用于ul添加li的情况,给ul添加一个click事件后,所有的li点击(包括ul后续新增的li)都能触发该事件,此即为事件委托
三.CSS
1.BFC
概念
bfc全称块级格式化上下文,是一种CSS的样式,类似一个容器,在里面的内容不会影响到外面的内容
触发
- overflow不是visible
- display是inline-block、table-cell、flex、table-caption或者inline-flex
- float不是none
- position不是static或者relative
使用场景
- 解决两个div的外边距合并问题
- 解决浮动元素脱离的父元素之外的问题(清除浮动)
- 实现自适应两栏布局
四.Javascript
1.原型链
引用链接:segmentfault.com/a/119000002…
2.typeof和instanceof
概念
- typeof:用于判断数据的基本数据类型,返回值是一个字符串,常用于判断该数据是否已经定义,只要不是'undifined',那就是已经定义了。
- instanceof:返回值是一个布尔值,用户判断对象的原型链上是否有该对象构造函数的prototype属性,常用于判断该对象是否由该构造函数构造
3.闭包
定义
A函数中定义了B函数,将B函数作为返回值返回出去,外面接收者可以通过B函数访问到A函数中定义的变量,这便产生了闭包。一言蔽之,闭包是有权访问另一个函数作用域里变量的函数。
使用场景
- 单例模式
- 模拟私有属性
- 自调用函数
- 防抖
缺陷
容易造成内存泄漏
4.new关键字
作用原理
- 创建一个空对象obj
- 将构造函数的prototype属性赋值到obj嘚原型对象上(obj.proto = constructor.protoype)
- 将构造函数的this指针指向obj,并且执行构造函数的代码,给私有属性赋值(const res = constructor.apply(obj, args))
- 将res对象返回,这样获取到的res就是实例
5.this指针
核心判断
哪个对象调用函数,函数里面的 this 指向哪个对象。
场景
- 方法调用模式下,this 总是指向调用它所在方法的对象,this 的指向与所在方法的调用位置有关,而与方法的声明位置无关(箭头函数特殊);
- 函数调用下,this 指向 window ,调用方法没有明确对象的时候,this 指向 window,如 setTimeout、匿名函数等;
- 构造函数调用模式下,this 指向被构造的对象;
- apply,call,bind 调用模式下,this 指向第一个参数;
- 箭头函数的this看他上一级的函数的this,如果没有上一级函数,则指向window,如果上一级函数是普通函数,则指向调用上一级函数的对象,如果上一级函数是箭头函数,则按照前面的规则继续往上查找,
- 严格模式下,如果 this 没有被执行环境(execution context)定义,那 this是 为undefined,非严格模式则是window
6.作用域
类型
- 静态(词法)作用域:函数的作用域链从函数定义的地方开始查找(JavaScript)
- 动态作用域:函数的作用域链从函数执行的地方开始查找(bash) 全局作用域:全局定义,window对象的属性,所有函数都能访问 函数作用域:函数内部定义,本函数外部无法访问 块级作用域:用let和const定义,作用域代码块({})
作用域链
访问变量,如果当前作用域内没有,会一级一级往外找,直到全局作用域,还是没有,则为undifined
作用域链延长
- try...catch... catch里面的e的作用域为catch代码块
- with(obj){} obj的作用域为with代码块
变量提升
- var定义的变量在函数作用域和全局作用域能提升到作用域的最前面,在定义前访问为undifined
- let和const定义的变量在其块级作用域中存在暂时性死区(块开始至该定义的代码行),死区内访问会导致error
const,let和var的区别
var变量会进行申明提前,在赋值前可以访问到这个变量,值是undefined。- 块级作用域也有“变量提升”,但是行为跟
var不一样,块级作用域里面的“变量提升”会形成“暂时性死区”,在申明前访问会直接报错。 - var 定义的变量可以反复去定义,let 和 const 不可以
- var 定义的变量在循环过程中无法保存,let 和 const 可以
- const 不能在 for 循环中定义,对于
for...in和for...of循环是没问题的 - var声明的变量会挂载到 window 全局对象上,let 和 const 不会
7.继承
8.es6
- 新增symbol类型 表示独一无二的值,用来定义独一无二的对象属性名;
- const/let 都是用来声明变量,不可重复声明,具有块级作用域。存在暂时性死区,也就是不存在变量提升。(const一般用于声明常量);
- 变量的解构赋值(包含数组、对象、字符串、数字及布尔值,函数参数),剩余运算符(...rest);
- 模板字符串(
${data}); - 扩展运算符(数组、对象);;
- 箭头函数;
- Set和Map数据结构;
- Proxy/Reflect;
- Promise;(手写promiseAll,理解Promise实现原理)
- async函数;
- Class;
- Module语法(import/export)。
五.网络
1.原生ajax
2.浏览器从输入Url到渲染页面,发生了什么
1.网络篇:
- 构建请求
- 查找强缓存
- DNS解析
- 建立TCP连接(三次握手)
- 发送HTTP请求(网络请求后网络响应) 2.浏览器解析篇:
- 解析html构建DOM树
- 解析css构建CSS树、样式计算
- 生成布局树(Layout Tree) 3.浏览器渲染篇:
- 建立图层树(Layer Tree)
- 生成绘制列表
- 生成图块并栅格化
- 显示器显示内容
- 最后断开连接:TCP 四次挥手
- (浏览器会将各层的信息发送给GPU,GPU会将各层合成,显示在屏幕上)
3.tcpudp
- TCP:面向连接,可靠传输,使用流量控制和拥塞控制,只是一对一通信,面向字节流,首部最小20字节,最大60字节,适用于要求可靠传输的应用,例如文件传输
- UDP:无连接,不可靠传输,不使用流量控制和拥塞控制,支持一对一,一对多,多对一和多对多交互通信,面向报文,首部开销小,仅8字节,适用于实时应用(IP电话,视频会议,直播等)
4.http和https的区别
- http的URL以'http://'开头,而https的URL以'https://'开头
- http是不安全的,而https是安全的
- http标准端口是80,而https的标准端口是443
- http工作于应用层,而https工作在传输层
- http无法加密,https对数据进行加密
- http无需证书,而https需要CA机构颁发的SSL证书
5.get和post区别
- GET在浏览器回退时是无害的,而POST会再次提交请求。
- GET产生的URL地址可以被Bookmark,而POST不可以。
- GET请求会被浏览器主动cache,而POST不会,除非手动设置。
- GET请求只能进行url编码,而POST支持多种编码方式。
- GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
- GET请求在URL中传送的参数是有长度限制的,而POST没有。
- 对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
- GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
- GET参数通过URL传递,POST放在Request body中
6.cookie和session的区别
7.XSS,CSRF,DDOS
xss:
攻击的目标为浏览器,通过写恶意脚本进行跨站篡改浏览器正常信息展示,窃取用户信息
- 反射型:发送请求时,XSS恶意代码代码出现在url中,作为输入提交到服务器端,服务器返回信息时,额外返回一些隐私信息
- 存储型:浏览器发送具有攻击性的脚本让服务器保存在数据库中,后续服务器响应请求的时候额外携带隐私信息返回
- DOM型:通过DOM来动态修改页面内容,从客户端获取DOM中的数据并在本地执行,利用JS脚本来实现XSS漏洞的利用,比如
防御措施
- 输入过滤:将用户输入的内容进行过滤,对所有用户提交内容进行可靠输入验证,包括URL,查询关键字,POST数据等。
- 输出转义:往HTML标签之前插入不可信数据的时候,要对数据进行HTML Entity编码(如空格转化为"$bnsp;")
- 使用HttpOnly Cookie选项:这样的话js脚本将不能访问客户端存储的cookie,避免了上述DOM型的xss攻击
xscf:
伪造请求,冒充用户在站内的正常操作。用户登录在一个正常网站比如银行网站,客户端保留cookie以及sessionid,攻击者让用户登录到攻击者的网站,在攻击者的网站访问银行网站进行一些转账汇款等非法操作,此时用户使用的cookie和sessionid都是正确的,银行网站会误以为是正常的用户操作。
防范措施
- 验证HTTP Referer字段:利用HTTP头中的Referer判断请求来源是否合法,Referer记录了该HTTP请求的来源地址
- 在请求地址中添加token并验证:xscf核心就是获取到客户端的cookie来伪造,但是token不存放于cookie,无法伪造
- 在HTTP头中自定义属性验证:也是使用token,但是和上述不同的是,并不是放在http请求中,可以通过XMLHttpRequest一次性给所有该类请求加上统一的token,解决上述在每个请求体中放入token的不便
ddos:
又称分布式拒绝服务,利用大量的请求造成资源过载,导致服务不可用
防范措施
- 限制单IP请求频率
- 防火墙等防护设置禁止ICMP包等
- 检查特权端口的开放
8.hhtp特性以及状态码
- 200响应成功
- 301永久重定向
- 302临时重定向
- 304资源缓存
- 403服务器禁止访问
- 404服务器资源未找到
- 500 502服务器内部错误
- 504服务器繁忙
- 1xx 信息状态码 接受请求正在处理
- 2xx 成功状态码 请求正常处理完毕
- 3xx 重定向状态码 需要附加操作已完成请求
- 4xx 客户端错误状态码 服务器无法处理请求
- 5xx 服务器错误状态码 服务器处理请求出错
9.http三次握手四次挥手
三次握手
- 1.刚开始客户端处于Closed状态,服务器处于Listen状态。客户端向服务端发送一个SYN报文(SYN=1),并指明客户端的初始化序列号seq=x,此时客户端处于SYN_Send状态
- 2.服务器收到后,发送SYN报文作为应答(SYN=1),并指明服务端的序列号seq=y,同时发送ACK=1,ack=x+1表明是响应报文,并且ack的值是客户端序列号加1,此时服务器处于SYN_RCVD状态
- 3.客户端收到后,发送ACK=1,ack=y+1(响应值是服务器序列号加1),seq=x+1(序列号++),此时客户端处于Establised状态,服务器收到后,也处于Establised状态,至此,两边建立了链接
为什么要三次握手
因为只有经过三次握手才能确认双方的收发功能都正常,缺一不可
序列号是固定的吗
序列号随时间变化,动态生成,因为如果是固定的,攻击者很容易猜出后续的序列号
三次握手过程中可以携带数据吗
只有第三次握手可以携带,即SYN=1的时候不能携带,第三次的时候客户端已经处于Establshed状态,已经建立了链接,所以可以正常发送数据
半连接队列
服务器第一次收到客户端的SYN后,处于SYN_RCVD状态,此时服务器会把这种状态下的请求放在半连接队列里,后面三次握手完成后的请求会放到全连接队列里,如果队列满了就可能会出现丢包
sYN洪泛攻击
客户端在短时间内伪造大量不存在的IP地址,向服务器不断发送SYN包,大量消耗服务器资源,使其半连接队列被占满,正常的SYN请求因为队列满了被丢弃。导致网络瘫痪
如果第三次握手丢失
服务器发送完SYN-ACK包,如果未收到客户端响应的ACK,会发起首次重传,规定时间内还未收到,会进行第二次重传,系统可以设置最大重传次数,超过后,会把该链接信息从半连接队列里丢弃
四次挥手
- 1.刚开始两边都处于ESTABLISHED状态,客户端发起FIN=1报文,seq=u,停止发送数据,主动关闭TCP链接,此时客户端处于FIN_WAIT1状态,等待服务器的响应
- 2.服务器收到后,发送ACK=1,ack=u+1,seq=v,此时服务器处于CLOSE_WAIT状态,等待从本地用户发来的链接终端请求。此时TCP处于半关闭状态,客户端到服务器的链接释放,客户端收到服务器的ACK响应后,进入FIN_WAIT2状态,等待服务器发出的链接释放报文段。
- 3.如果此时服务器也想断开链接了,和客户端第一次挥手一样,发送FIN=1,ACK=1,seq=w,ack=u+1,此时服务端处于LAST_ACK状态,等待原来发向远程TCP的链接中断请求的确认
- 4.客户端收到FIN后,发送ACK=1,seq=u+1,ack=w+1,此时客户端处于TIME_WAIT状态,等待足够的时间以确保远程TCP收到了链接中断请求的确认(此时由服务器到客户端的TCP链接并未释放掉,需要经过时间等待计数器设置的时间2MSL(一个报文的来回时间)后才会进入CLOSED状态,这是为了确保服务器收到自己的ACK报文,因为如果服务器在规定时间内没收到客户端的ACK报文,会重新发送FIN报文(第三次挥手)给客户端,客户端就知道前面发的ACK报文丢失,会再次发送ACK报文)
为什么要四次挥手
因为由于TCP的半关闭特性,提供了链接的一端在结束他的发送后还能接收来自另一端的数据的能力,两次挥手可以释放一端到另一端的TCP链接,四次才能释放两边倒对方的链接。
10.http1.0,http1.1,http2.0的群别
http1.0和http1.1
- http1.1引入了更多的缓存控制策略
- http1.1优化带宽及网络链接的使用,在请求头引入了range头域,允许只请求资源的某个部分,以便实现断点续传
- http1.1新增了24个错误状态响应码
- http1.1支持Hots头处理
- http1.1支持长链接和请求的流水线处理,在一个TCP链接上可以传送多个HTTP请求和响应,默认开启Connection:keep-alive,一定程度上弥补了http1.1每次请求都要创建链接的缺点
http2.0和http1.1
- 多路复用,http2.0通过让所有数据流共用同一个TCP链接,可以更高效的利用TCP的慢启动(TCP 连接会随着时间进行自我「调谐」,起初会限制连接的最大速度,如果数据成功传输,会随着时间的推移提高传输的速度。这种调谐则被称为 TCP 慢启动。由于这种原因,让原本就具有突发性和短时性的 HTTP 连接变的十分低效),让单链接多资源 的方式,减少服务端的链接压力,内存占用更小,提升传输速度
- 首部压缩,http2.0让支持该协议的客户端和服务器之间维护同一份相同的静态字典(包含常见的头部名称等)和动态字段(可以动态添加内容),这样那些method:GET或者cookie:xxxx字段都可以通过字典的键值对映射用单个字符来表示
- 服务器推送,HTTP2.0引入了server push,它允许服务端推送资源给浏览器,在浏览器明确地请求之前。一个服务器经常知道一个页面需要很多附加资源,在它响应浏览器第一个请求的时候,可以开始推送这些资源。这允许服务端去完全充分地利用一个可能空闲的网络,改善页面加载时间。
11.http如何实现缓存
-
强缓存==>Expires(过期时间)/Cache-Control(no-cache)(优先级高) 协商缓存 ==>Last-Modified/Etag(优先级高)Etag适用于经常改变的小文件 Last-Modefied适用于不怎么经常改变的大文件
-
强缓存策略和协商缓存策略在缓存命中时都会直接使用本地的缓存副本,区别只在于协商缓存会向服务器发送一次请求。它们缓存不命中时,都会向服务器发送请求来获取资源。在实际的缓存机制中,强缓存策略和协商缓存策略是一起合作使用的。浏览器首先会根据请求的信息判断,强缓存是否命中,如果命中则直接使用资源。如果不命中则根据头信息向服务器发起请求,使用协商缓存,如果协商缓存命中的话,则服务器不返回资源,浏览器直接使用本地资源的副本,如果协商缓存不命中,则服务器返回最新的资源给浏览器。
12.前端性能优化
- 浏览器缓存
- 防抖、节流
- 资源懒加载、预加载
- 开启Nginx gzip压缩
三个方面来说明前端性能优化
一: webapck优化与开启gzip压缩
- babel-loader用 include 或 exclude 来帮我们避免不必要的转译,不转译node_moudules中的js文件 其次在缓存当前转译的js文件,设置loader: 'babel-loader?cacheDirectory=true'
- 文件采用按需加载等等
- 具体的做法非常简单,只需要你在你的 request headers 中加上这么一句: accept-encoding:gzip
- 图片优化,采用svg图片或者字体图标
- 浏览器缓存机制,它又分为强缓存和协商缓存
二:本地存储
从 Cookie 到 Web Storage、IndexedDB 说明一下SessionStorage和localStorage还有cookie的区别和优缺点
三:代码优化
- 事件代理
- 事件的节流和防抖
- 页面的回流和重绘
- EventLoop事件循环机制
- 代码优化等等
13.跨域通信
跨域概念:由于同源策略(URL中协议,域名,端口必须完全一致),浏览器不能执行其他网站的脚本
- jsonp(利用script标签没有跨域限制的漏洞实现。缺点:只支持GET请求)
- CORS(设`Access-Control-Allow-Origin:指定可访问资源的域名)
- postMessage(message, targetOrigin, [transfer])(HTML5
新增API 用于多窗口消息、页面内嵌iframe消息传递),通过onmessage`监听 传递过来的数据 Websocket是HTML5的一个持久化的协议,它实现了浏览器与服务器的全双工通信,同时也是跨域的一种解决方案。Node中间件代理Nginx反向代理- 各种嵌套
iframe的方式,不常用。 - 日常工作中用的最对的跨域方案是CORS和Nginx反向代理
14.浏览器的本地存储
Cookie
始终在同源的http请求中携带,数据不能超过4k,只在设置的cookie过期时间之前有效,即使窗口关闭,在所有的同源窗口中共享
sessionStorage
可以达到5m,仅在当前浏览器窗口关闭之前有效(刷新有效),不在不同的浏览器窗口中共享(即使是同源或者同一页面)
localStorage
可以达到5m,即使窗口关闭也有效,本地存储,用作持久保存数据,在所有的同源窗口中共享,除非手动删除
六.Vue
1.双向绑定
2.MVVM
是一种模型,分为Model,view,ViewModel,Model定义数据和业务逻辑,View代表UI视图,负责数据展示,ViewModel负责监听Model中数据的改变并且控制视图的更新,处理用户交互操作,ViewModel和Model之间有着数据双向绑定,View中由于用户交互产生的变化会同步到Model,Model中数据改变也会在View上实时刷新。
3.computed,watch,methods
computed
计算属性,依赖其他属性值,并且computed的值有缓存,只有依赖的属性值发生改变,下一次获取computed的值时才会重新计算computed的值,适用于需要进行数值计算,并且依赖其他数据的场景
watch
侦听器,无缓存,观察作用,类似于监听回调,每当监听的数据发生变化都会执行调用进行后续操作,适用于在数据变化时需要进行异步操作的场景
methods
computed和method都可以定义函数,但是computed必须要依赖的属性进行变化才能触发该函数,method则每次调用都能触发
4.生命周期
beforeCreate
- 实例初始化之后,this指向创建的实例,不能访问到data,computed,watch,methods上的方法和数据
- 常用于初始化非响应式变量
created
- 实例创建完成,可访问data,computed,watch,methods上的方法和数据,未挂载到DOM,不能访问到ref属性内容为空数组
- 常用于简单的ajax请求,页面的初始化
beforeMount
- 在挂载开始之前被调用,beforeMount之前,会找到对应的template,并编译成render函数
mounted
- 实例挂载到DOM上,此时可以通过DOM API获取到DOM节点,$ref属性可以访问
- 常用于获取VNode信息和操作,ajax请求
beforUpdate
- 响应式数据更新时调用,发生在虚拟DOM打补丁之前
- 适合在更新之前访问先用deDOM,比如手动移除已添加的事件监听器
updated
- 虚拟DOM重新渲染和打补丁之后调用,组件DOM已经更新,可执行依赖于DOM的操作
- 避免在这个钩子函数中操作数据,可能陷入死循环
beforeDestroy
- 实例销毁之前调用。这一步,实例仍然完全可用,this仍能获取到实例
- 常用于销毁定时器,解绑全局事件,销毁插件对象等操作
destroyed
- 实例销毁后调用,调用后,Vue实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁
5.diff算法
6.v-for中的key
当 Vue 正在更新使用 v-for渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。 这种做法非常消耗性能,但是如果添加了key,Vue会基于key是否相同来移动元素,尽可能用现存的元素移动位置来进行渲染,可以显著提升性能。
7.组件通信
props/$emit
- 父组件向子组件传值,父组件通过props向下传递数据给子组件,组件中的数据共有data,props,computed三种形式
- 子组件向父组件传值(通过事件方式),子组件通过events给父组件发送消息,实际上就是子组件把自己的数据发送到父组件
$emit/on
这种方法通过一个空的Vue实例作为中央事件总线,用它来触发事件和监听事件。
- var Event = new Vue();
- Event.$emit(自定义事件名,数据) (触发自定义事件)
- Event.$on(自定义事件名,数据处理函数) (自定义事件监听)
Vuex
$attrs/listeners
实现跨级通信
- attrs"传入子组件
- listeners"传入子组件
provide/inject
允许一个祖先组件向其所有子孙后代注入一个依赖,解决了跨组件间的通信问题,主要使用场景是子组件获取上级组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系
$parent/children与ref
- ref,如果在普通的DOM元素上使用,引用指向的就是DOM元素,如果用在子组件上,引用就是指向组件实例
- children,访问父/子实例
8.v-model
v-model是一种语法糖,他的原理是通过v-bind绑定响应式数据,让数据变动,view视图能更新,同时通过oninput等事件获取改变后的value,赋值绑定的数据,实现view视图变化,数据变动。
9.Vue.nextTick
在下次DOM更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后deDOM,即当数据更新了,在dom中渲染完成后,自动执行该函数内容。 主要用于在视图更新之后,基于新的视图进行操作,在mounted阶段,如果需要操作渲染后的视图,也要使用nextTick方法。
10.keep-alive
被keepalive包含的组件不会被再次初始化,也就意味着不会重走生命周期函数,在组件切换过程中他会缓存包含的不活动的组件实例,而不是销毁他们。
- activated:当keepalive包含的组件再次渲染的时候触发
- deactivated:当keepalive包含的组件销毁的时候触发 keepalive可以接收三个属性作为参数进行匹配对应的组件进行缓存
- include:包含的组件(可以为字符串,数组,以及正则表达式,只有匹配的组件会被缓存)
- exclude:排除的组件(可以为字符串,数组,以及正则表达式,任何匹配的组件都不会被缓存)
- max:缓存组件的最大值
11.Vuex
12.vue性能优化
- 编码阶段 尽量减少data中的数据,data中的数据都会增加getter和setter,会收集对应的watcher
- v-if和v-for不能连用 如果需要使用v-for给每项元素绑定事件时使用事件代理
- SPA 页面采用keep-alive缓存组件
- 在更多的情况下,使用v-if替代v-show
- key保证唯一
- 使用路由懒加载、异步组件
- 防抖、节流
- 第三方模块按需导入
- 长列表滚动到可视区域动态加载
- 图片懒加载
- SEO优化
- 预渲染
- 服务端渲染SSR
- 打包优化
- 压缩代码
- Tree Shaking/Scope Hoisting
- 使用cdn加载第三方模块
- 多线程打包happypack
- splitChunks抽离公共文件
- sourceMap优化
- 用户体验
- 骨架屏
- PWA
- 还可以使用缓存(客户端缓存、服务端缓存)优化、服务端开启gzip压缩等
13.webpack
juejin.cn/post/702324… juejin.cn/post/703932…