《高性能JavaScript》第6-8章
2021-11-09 本文已影响0人
前端艾希
一、快速响应的用户界面
浏览器限制JavaScript
运行时间的策略:
- 自脚本开始执行以来的执行语句数量;
- 记录脚本执行的总时长;
Robert Miller
在1968年的研究中提到单个脚本操作不应该超过100ms
,后来一些学者也重申了相近的观点。因为当界面在100ms
内无法响应用户的操作的话,用户就会觉得失去了对界面的控制。
1.1 解决单个脚本任务执行时间过长的办法
因为JavaScript
线程和UI
线程是互斥的,所以我们需要一些办法避免单个脚本占用过多CPU
时间:
- 首先检查代码是否有死循环,或者递归不能正常推出等情况,一般来说出现这种情况浏览器会提示,但是像在
webview
和微信小程序中是没有提示的; - 检查循环语句中单任务的执行时间,如果时间过长,那么需要使用
setimeout
将n
个同步任务变成异步任务; - 如果一个函数运行时间过长,也可以把函数任务进行拆分;
- 将
CPU密集型
任务单独交给worker
执行。
二、Ajax
使用Xhr
时如何选择post
和get
:
-
get
的响应会被缓存,如果需要多次请求统一数据,优先考虑get
; - 浏览器对
get
请求的url
长度有限制,所以当get
的searchParams
和url
长度加起来太长时(chrome为4096),需要使用post
;
2.1 Ajax性能指南
最快的ajax
就是没有请求,有两种方法可以避免发送不必要的请求:
- 在服务端,通过设置
HTTP
头来确保响应被缓存; - 在客户端,把获取到的信息主动缓存起来,从而避免再次请求。
2.2 Ajax优化建议
- 减少请求数,可以通过合并
JavaScript
和CSS
,对于图片等可以使用MXhr
技术; - 合理使用
HTTP
缓存和客户端缓存;
三、编程实践
3.1 避免双重求值
JavaScript
有4种方法可以让我们在程序中提取一个包含代码的字符串,然后动态执行,分别是:eval
、Function
构造函数、setTimeout
,setInterval
。当我们在JavaScript
代码中执行另一段JavaScript
代码时就会导致双重求值,造成性能损耗。因为每次调用这些方法时都需要重新创建一个新的解释器实例,所以会比直接执行慢得多。
3.2 避免重复性工作
当一个函数被多次调用,并且函数内有重复性工作时,那么它应该被优化,可用的手段有:
- 延迟加载,即第一次调用的时候,将重复性工作的结果应用到之后的调用中。
- 条件预加载,在第一次调用之前,完成重复性工作内容,并把结果应用到之后的调用中。
3.3 使用速度更快的部分
在JavaScript
中,位运算要比数学运算和布尔操作快得多,所以有些场景使用位运算会节省大部分时间。举个例子,我们在做表格的斑马条纹时,会通过表格的索引的奇偶来添加相应的类或者样式:
// 数学计算
for (let i = 0; i < len; i++) {
if (i % 2) {
className = 'even';
} else {
className = 'odd';
}
}
// 位运算,大约快50%左右
for (let i = 0; i < len; i++) {
// 奇数的最后一位必定是1,和1的按位与的结果是1
if (i & 1) {
className = 'odd';
} else {
className = 'even';
}
}
另外,在JavaScript
中做数学运算的时候,尽量使用Math
对象,因为这上面的方法是浏览器原生实现的,都是经过编译后的机器码,即使解释器再优化,原生方法的速度必定快于JavaScript
代码。