前言
你是不是觉得一天天的代码写过去写过来都一个样,没什么新鲜感?
这样会导致你出现一种错觉,“哎,Web前端好简单呀,Vue好简单呀,React一点儿也不难”,公司安排的任务我都能完成的错觉
其实现实情况就是我们还有很多东西需要学习,需要实践,我们还差得很远哟~~~
下面是我使用过的优化方式,优先级从前到后,大家如果有其它比较nice的优化方式,让我来试试呀,么么哒
性能测试网站吧~
HTTP2
http/1.1问题
-
对于同一个域名,浏览器最多只能同时创建 6~8 个 TCP 连接 (不同浏览器不一样) 。
-
合并文件、内联资源、雪碧图、域名分片对于 HTTP/2 来说是不必要的,使用 h2 尽可能将资源细粒化,文件分解地尽可能散,不用担心请求数多,所以h1的优化方式不是很实用哟。
-
我们的 JD 就是使用了HTTP2的代表,所以使用HTTP2是应该是立即的
图片
- 懒加载(
Intersection Observer) - 压缩
- 尽量保证图片尺寸大小正确
- 避免空的
src - 采用下一代格式图片WebP 兼容性最好, JD 老大哥也在使用哦
网络
- CDN
- 域名预解析
rel=dns-prefetch - 内容预加载
rel=preloadorprefetch
Gzip
- 通过request的
Accept-Encoding可以判断客户端接受哪些压缩方法 - 服务端通过
Content-Encoding说明当前服务器的压缩方式 - 前端可以通过webpack生成gz文件,这样服务器就不需要做这一步了
资源加载顺序
css加载
- CSS会阻塞渲染树的构建,不阻塞DOM构建
- 但是在CSSOM构建完成之前,页面不会开始渲染(一片空白)
- js虽然会阻塞后续DOM构建,但是前面已经就绪的内容会进行渲染
- CSS虽然不阻塞DOM构建,但是会阻塞后面js的执行,从而间接阻塞完整DOM的构建
- 测试发现,后边的js虽然先下载下来,但是只有等css执行完毕后,才得到执行
- 然后进一步js又会阻塞后续DOM树构建,就这样导致整个渲染过程话费更多时间。所以我们要尽快加载CSS并构建CSSOM。
- 所以应该尽快加载css文件好生成对应的CSSOM
js加载
- JS默认也是会阻塞DOM和渲染树的构建的
- 声明为defer的脚本会延迟到DOM构建完成后(DOMInteractive事件),DOMContentLoaded和window.onload事件之前执行(但依然会被浏览器的预加载策略提前下载)。
- 只针对外联脚本有效。多个defer会按照先后顺序串行执行。
- 声明为async的脚本会异步地下载和执行,会在window.onload事件之前执行,但是可能会在DOMContenLoaded事件前后执行。
- css和js文件会比图片有更高的优先级
通过上面就能理解为什么CSS文件放在head中,JS放在body底部了,但是一些特殊的JS还是需要放在head中的,例如babel-polyfill.js文件、flexible.js。
代码优化
document.write
会阻塞页面渲染,尤其注入一段脚本就更夸张了
eval
eval 将传入的字符串当做脚本执行,会大幅度降低脚本执行性能
全局变量
全局变量的查找作用域链更长,生命周期也更长,且有内存泄漏的风险,甚至会产生不可预估的 bug 出现。项目中的第三方库一般都会暴露一些全局变量,这和你声明的全局变量也可能会发生冲突。所以,尽量谨慎地使用全局变量
循环操作优先级(从小到大)
for-forEach/for-of/map/filter-for-in- 最慢的属于
for-in,它之所以慢,是因为它常用于对象属性的遍历,并且会访问自身属性以及其原型链的属性(包括不可枚举属性) - 减少循环中的活动 例如把
xx.length放在for外面 - 尽量不要在循环中声明函数
尽量少地使用闭包
- 闭包提供了一些便捷性,但同时也会有一些性能影响,由于保留着原应被回收的变量引用,增加了作用域链的长度,影响性能。
- 同时它会可能会有
内存泄漏的风险。
判断语句if/switch
- 当超过三个判断尽量使用
switch if量提前return,或者使用三元操作符
===/!==
== 和 != 操作符会引起 JS 的数据类型隐式转换,导致一些不可预估的负面作用,所以,更明智的选择是,总是去使用 === 和 !== 进行相等判断
New
通过 new 操作符新建一个对象,类似于函数调用,同时会做一些关联原型链等操作,性能会慢很多,字面量则在写法上更直观友好且高效
操作DOM
现在是个前端都知道操作DOM消耗性能,哈哈哈哈
事件绑定
能使用事件委托的都使用事件委托
Thanks