性能优化紧急回顾笔记
最近无聊,又开始刷书,写写《高性能JavaScript》读后感吧!
1、脚本加载
脚本加载会阻塞其他文件下载,页面会等到所有JavaScript代码下载并执行完成才能继续
解决方法:(1)、建议将script标签放在body底部,确保脚本执行前页面已完成渲染
(2)、可以将某些脚本直接写在script标签插入html中,进行首屏优化
(3)、使用webpack等工具打包或压缩代码,减少请求与文件体积
2、数据存取
数据有四种方式,字面量、本地变量、数组、对象
多层引用,例如window.location.href、原型链搜索等,如果使用多次,建议进行本地储存
比如:h = window.location.href
3、DOM
DOM操作很慢,原因有2:DOM节点很复杂、修改DOM会导致重绘(repaint)和重排(reflow)
(1)、插入节点推荐使用innerHTML,大量字符串建议使用数组拼接
(2)、HTMLCollection集合是动态检测,如果对象更新,对应的集合也更新,无论是获取还是修改都会触发一次
(3)、比较通用的优化方法,缓存(类)数组长度,再进行循环遍历操作
(4)、重排、重绘都是代价昂贵的操作,尽量减少发生。
(5)、事件委托
tips:重绘、重排
浏览器下载完页面中所有组件-HTML标记、JavaScript、CSS、图片-之后(这里有误,边下载边渲染)会解析并生成两个内部数据结构:
DOM树 => 表示页面结构
渲染树 => 表示DOM节点如何显示
DOM树中的每一个需要显示的节点在渲染树中至少存在一个对应的节点(隐藏的DOM元素在DOM树中没有对应节点)。
当DOM变化影响了元素的几何属性(宽或高),浏览器需要重新计算元素的几何属性。浏览器会使渲染树中受到影响的部分失效,重新构造渲染树,这个过程叫‘重排(reflow)’;完成重排后,浏览器会重新绘制受影响的部分到屏幕中,该过程称为‘重绘(repaint)’。
当改变颜色时,只会引起重绘。
重排发生条件:
1、添加、删除可见元素
2、元素位置改变
3、元素尺寸改变
4、内容改变
5、页面渲染初始化
6、浏览器窗口尺寸改变
浏览器会通过队列化修改(类似于task)来优化重排过程。然而,当获取类似于offsetTop、getComputedStyle等属性时,会强制浏览器渲染已获取最近属性。
当需要对DOM做多次操作时,有三种方式优化:
1、将DOM隐藏,操作完后显示
2、构建文档碎片,插入DOM(推荐)
3、创建一个DOM备份,操作完后替换原DOM
4、算法与流程
(1)、倒序+缓存长度优化循环:
// 某数组
var arr = [];
// 循环处理元素
for (var i = 0; i < arr.length; i++) {
process(arr[i]);
}
// 优化循环体
for (var i = arr.length; i--;) {
process(arr[i]);
}
(2)、贴一个Duff's Device,通过分割循环次数提升效率:
// Duff's Device
var iterations = Math.floor(items.length / 8), // 表示多少轮循环
startAt = items.length % 8, // 8的余数
i = 0; // 从0开始迭代
do {
// 首次执行把余数消灭
switch (startAt) {
case 0:
process(items[i++]);
case 7:
process(items[i++]);
case 6:
process(items[i++]);
case 5:
process(items[i++]);
case 4:
process(items[i++]);
case 3:
process(items[i++]);
case 2:
process(items[i++]);
case 1:
process(items[i++]);
}
startAt = 0;
} while (--iterations);
优化后的算法,取消了switch语句,将余数与整数分别处理:
// 余数
var i = item.length % 8;
while (i) {
process(item[i--]);
}
// 整数
i = Math.floor(item.length / 8);
while (i) {
process(items[i--]);
process(items[i--]);
process(items[i--]);
process(items[i--]);
process(items[i--]);
process(items[i--]);
process(items[i--]);
process(items[i--]);
}
(3)、if-else与switch
条件增加时,优化使用switch,性能与代码可读性方面都更好。(在JS中switch使用全等,没有隐式类型转换带来的损耗)
优化if-else:将最可能出现的情况放在第一项
(4)、查找表
使用数组或普通对象来构建查找表。
5、Ajax
请求:
(1)、正常ajax请求
使用XHR时,POST与GET的对比。
对于不会改变服务器状态,只会获取数据(幂等行为)的请求,应该使用GET,GET请求的数据会被缓存起来,多次请求有助于提高性能。
当URL加上参数长度过长使用POST。
(2)、动态脚本注入
这种技术克服了XHR最大限制:不能跨域。
该方法通过创建一个script标签, 将src设置为不同域的URL。
动态脚本注入的控制有限,无法设置请求头,只能通过get传参。
缓存:
(1)、在服务端,设置HTTP头信息以确保你的响应会被浏览器缓存
通过get方式发送请求,并在响应中发送正确的HTTP头信息,Expires头信息会告诉浏览器缓存响应多久。
(2)、在客户端,把获取到的信息存储到本地,从而避免再次请求
6、finally
(1)、文件合并(webpack)
(2)、文件压缩
(3)、缓存
(4)、CDN
完结撒花!