TL;DR
避免对可视化更新使用
setTimeout
或setInterval
; 始终使用requestAnimationFrame
将长时间运行的 JavaScript 从主线程移动到 Web Workers
使用微任务进行跨越多个帧的 DOM 更改
使用开发者工具的timeline和JavaScript Profiler评估JS性能
使用requestAnimationFrame
改变视觉表现
requestAnimationFrame
可以在帧的开始运行一个指定的回调。
1 | /** |
框架或示例可能会使用 setTimeout
或 setInterval
来进行动画等可视化更改,但问题是回调会在帧中的某个点运行,可能就在帧的最后,这通常会导致我们错过一个帧,从而导致 jank
。
jQuery过去使用setTimeout处理动画行为,在版本3之后改用requestAnimationFrame,强烈建议patch旧版本的jQuery。
减少复杂性或者用Web Workers
js运行在主线程,还有其他注入样式计算布局和绘制等任务。如果JS运行太久就会阻塞这些任务,导致丢帧。
如果使用滚动动画,将JS保持3到4ms。如果处于idle时期,就无所谓了。
许多情况下,不需要DOM访问的计算操作可以转移到web workers。例如排序或者搜索非常适合这个模型,加载和生成模型也可以。
1 | var dataSortWorker = new Worker("sort-worker.js"); |
并不是所有的工作都适合这种模式: webworkers 没有 DOM 访问权限。如果您的工作必须在主线程上进行,那么考虑一种批处理方法,将较大的任务分割为微任务,每个任务的执行时间不超过几毫秒,并在 requestAnimationFrame 处理程序内部跨每一帧运行。
1 | var taskList = breakBigTaskIntoMicroTasks(monsterTaskList); |
这种方法影响UX和UI,您需要确保用户知道任务正在被处理,通过使用进度或活动指示符。在任何情况下,这种方法都可以保持应用程序的主线程空闲,帮助它保持对用户交互的响应。