优化JavaScript的执行
JavaScript经常会触发一些页面视觉上改变,有时候是直接改变样式,有时候是更新页面数据,有时候是执行一些动画效果等等。JavaScript运行时间通常是影响性能的关键因素,所以接下来我们可以看一下如何去尽量减小这些因素的影响。
JavaScript的性能分析可能是一门艺术了,因为你所写的JavaScript代码和实际执行时的完全不同。如今的浏览器都采用的是JIT(Just In Time)编译器,同时会使用各种优化技巧以供最快速的执行,但是正因为如此却改变了代码本来的动态性。
如上所言,那么下面会给出一些建议来帮你更好的执行JavaScript代码
TL;DR
- 使用
requestAnimationFrame代替setTimeout或者setInterval来处理页面上的视觉变化 - 考虑使用Web Worker来将需要在主线程长时间运行的JavaScript代码迁移
- 将大的耗时任务拆分为多个task分为几帧完成
- 使用Chrome DevTools中的Timeline和JavaScript Profiler来观测对JavaScript的影响因素
使用requestAnimationFrame做动效
某些情况下在页面视觉上发生变化时,你可能想正好在每一帧开始时执行某些操作,那么requestAnimationFrame是唯一可以准确保证在每一帧执行前执行JS代码的方法
/**
* 作为requestAnimationFrame的回调函数,会在每帧开始前执行
*/
function updateScreen(time){
// ...
}
requestAnimationFrame(updateScreen);
一些框架或者示例可能使用setTimeout或者setInterval来做一些视觉上的变动比如动画,但是问题是无法确定这些回调函数的执行时间点,有可能恰巧是在每帧的结尾,那就可能导致帧丢失,从而导致页面卡顿,这完全不是我们想要的。
实际上jQuery以前也用setTimeout来执行动画,在后来的版本中改用requestAnimationFrame了,如果你还在使用旧版本的话可以检查一下,有必要可以考虑升级。(应该人很少了吧)
减少复杂度的或者使用Web Worker
JavaScript运行在浏览器的主线程上,与此同时主线程还要执行样式计算,布局,绘制等等。如果JavaScript代码长时间执行则会阻塞这些任务,就可能出现帧丢失的情况。
所以需要考量JavaScript代码的执行时间点和执行时长。举个例子:如果在执行滚动操作,那么理想情况下应该保持JS代码的执行时间保持在3~4ms内,如果超过这个时间,就要考虑采取优化手段了,如果是在空闲时间段那就可以放宽时间限制了。
很多情况下如果不需要访问DOM,就可以把一些纯计算的工作交给Web Worker去执行,对于数据的处理或者搜索排序等等操作都非常适合在这里处理
const dataSortWorker = new Worker('sort-worker.js');
dataSortWorker.postMessage(dataToSort);
// 主线程则可以做其他事情
dataSortWorker.addEventListener('message',(e)=>{
const sortedData = e.data;
// ...
})
也不是所有情况都适合:Web Worker无法访问DOM。在必须在主线程执行的工作,可以考虑采用批处理方法,什么意思呢?就是把较大的任务分割成多个task,每个task不超过几毫秒,并且放在requestAnimationFrame中,让其在每帧的开始去执行。
const taskList = breakBigTaskIntoMicroTasks(monsterTaskList);
requestAnimationFrame(processTaskList);
function processTaskList(taskStartTiem){
let taskFinishTime;
do {
// 假设下一个task已经推到栈里了
const nextTask = taskList.pop();
// 执行下一个task
processTask(nextTask);
//
taskFinishTime = window.performance.now();
} while(taskFinishTime - taskStartTime < 3);
if(taskList.length > 0){
requestAinmationFrame(processTaskList);
}
}
这种处理方法同时需要从UX和UI方面考虑,可以加一个进度标识图标以便让用户知晓任务正在执行。不管怎样它都可以保证程序的主线程是空闲状态,因此不会影响用户交互行为。
知晓JavaScript的帧的副作用
在评估一个库或者一个框架亦或自己的代码时,逐帧分析JS代码的执行消耗的时间是很必要的。特别是在动画或者一些过渡效果方面时尤为重要。
Chrome DevTools提供的Performance功能是查看JS每帧执行消耗时间的非常好的工具。
通过这个工具提供的信息分析后就可以找出影响性能的原因,如我们之前所提到的,如果在主线程中长时间执行的JS代码是非必要的就可以把它移到Web Worker中来让主线程执行其他任务。【Performace的使用方法】
原文地址:渲染性能分析(二)