网络优化
-
DNS预解析
借助HTML提供的
<link ref="dns-prefetch" href="xxx" />标签,可以对可能访问的其他源的域名进行前置的DNS解析。但需要注意的是href填写的内容应该是跨源的,因为当浏览器看到这个link标签时,你的文档已经被下载并开始执行了。也可以配合preconnect进一步结合,preconnect是预链接,还包含了三次TCP握手,或者https的TLS握手,但是需要注意的是preconnect最好只针对关键链接,而非所有,否则适得其反。 -
缓存
从缓存中快速获取数据,减轻服务器压力,主要有以下两种
- 强制缓存:主要依赖于header中的
Expire(Http1.0)或Catch-Control字段的max-age,判断当前缓存是否过期,Expire是过期时间,max-age是相对过期时间 - 协商缓存:主要依赖
E-Tag和Last-Modified两个字段实现,浏览器在请求一个资源时向浏览器发送一个请求,携带上这两个字段,服务器通过这两个字段判断缓存是否有效,有效则返回一个304的状态码,并且不带相应报文,浏览器从缓存拿取资源。否则返回新的E-Tag和Last-Modified,以及相应报文。详细请戳这里
- 强制缓存:主要依赖于header中的
-
CDN(内容分发)
内容分发是一组分散在不同地理位置的服务器,上传到云上的资源会被同步到各个CDN节点,浏览器在请求资源时会到最近的相应最快的节点拉取资源。
-
响应内容压缩
浏览器通过请求头的
Accept-Encoding列出压缩方法,例如gzip,deflate,br,服务器收到请求后,采用浏览器告知的一种压缩方法对相应内容进行压缩,并将这种方法写入到响应头的Content-Encoding。 -
使用多域名
现代浏览器,对同一域名的请求,都限制有并发数,所以可以合理规划你的资源域名(太多了会导致DNS等其他损耗,保持在2-4个就好),通常可以将静态资源和接口分开,甚至对静态资源的图片、js、css等进行合理划分。
-
使用雪碧图
将一些小图做在一张大图上,既可以减少请求次数,也可以提前加载图片。
-
启用HTTP2.0
HTTP2.0提供了头部压缩,以及多路复用的特性
- 头部压缩:http1时代会提供一些压缩算法对请求体响应体进行压缩,2.0对头部也会进行压缩。而且同一个网站中的请求拥有很多相同的header内容,只有少部分的是不一致的,客户端和服务器都会维护一份header的哈希表,每次请求中,相同header并不会传输真正的内容。
- 多路复用:http2.0不再使用文本传输,避免了转义的损耗。采用二进制数据传输,在同一个TCP管道中对请求进行分片,把一个请求拆分成多个请求多个数据包,最终完成拼接。详细请戳
渲染优化
浏览器的渲染流程是根据css构建CSSOM树和DOM树,最终合成一棵渲染树,根据渲染树做布局(回流)绘制(重绘)
-
避免CSS阻塞
CSS会影响渲染树的构建,阻塞页面渲染,所以需要早快的加载CSS资源,将CSS放在Head里
-
避免JS阻塞
众所周知,浏览器是单线程的,在js执行时,页面停止渲染的。而且每一帧的流程也是对js执行、页面渲染做好妥帖安排的,如图一个完整的帧流程:
处理用户输入-》JS执行-》RAF-》解析HTML计算样式布局-》更新渲染树绘制-》RIC。所以要尽可能的减少JS的阻塞,可以利用defer:并行加载,文档加载完成执行和async:并行加载并执行。当然尽可能将js块放在body的最后边。 -
首屏加载优化
- 使用骨架屏,降低用户在等待时间白屏带来的焦躁感
- 资源按需加载,首页不需要的延迟加载
-
减少回流和重绘
- 对多个节点的处理,使用documentFragment
- translate替代top,visibility替代display,opacity替代visibility,因为top位置和display等的变化会导致回流,visibility会引起重绘
- 不要在循环里反复获取设置DOM节点的样式属性
- DOM读写分离,浏览器具有惰性渲染机制,多次修改DOM可能只触发浏览器的一次渲染。而如果修改DOM后,立即读取DOM。为了保证读取到正确的DOM值,会触发浏览器的一次渲染。因此,修改DOM的操作要与访问DOM分开进行
- 少用table,table的每一个单元格变化都会引起整个table的回流重绘
JS的性能优化
- 事件委托,降低事件绑定开销;子组件天然继承父组件事件
- 防抖节流
- 尽量不要用JS动画,CSS3的动画或者Canvas是更好的选择
- 利用WebWorker多线程能力,避免复杂计算影响浏览器主线程
打包优化
可以利用一些第三方的打包分析库,对打包产物进行分析,了解哪些可以排除,哪些可以分割。
- 代码分离,通过chunk配置,合理分割生成的打包产物,不要只生成一个庞大的index.js文件,也不要生成太多的需要首屏加载的资源文件
- 公共模块抽离,采用cdn加载,而非打包到自己的打包产物中
- 按需加载,合理利用treeShaking,将不需要的模块排除掉
- 合理利用第三方库对打包产物进行压缩