JavaScript 经常会触发视觉变化。有时是直接通过样式操作,有时是会产生视觉变化的计算,例如搜索数据或将其排序。时机不当或长时间运行的 JavaScript 是导致性能问题的常见原因。您应当设法尽可能减少其影响。
JavaScript 经常会触发视觉变化。有时 样式设置,有时是计算 会导致视觉变化,例如搜索数据或对数据进行排序。时机不合适 或长时间运行的 JavaScript 是导致性能问题的常见原因。 您应当设法尽可能减少其影响。
JavaScript 性能分析可以说是一门艺术,因为您编写的 JavaScript 与实际执行的代码完全不同现代浏览器都使用 JIT 编译器 尽可能加快执行速度, 会显著改变代码的动态。
尽管如此,您还是可以采取一些措施来帮助您的应用 JavaScript。
摘要
- 避免使用 setTimeout 或 setInterval 实现视觉更新;始终使用 requestAnimationFrame。
- 将长时间运行的 JavaScript 从主线程移到 Web Worker。
- 使用微任务来执行对多个帧的 DOM 更改。
- 使用 Chrome 开发者工具的 Timeline 和 JavaScript Profiler 来评估 JavaScript 的影响。
使用 requestAnimationFrame
实现视觉变化
当屏幕上发生视觉变化时,您希望在合适的时间
浏览器,位于帧的开头。只有一种方法可以保证
将使用 requestAnimationFrame
。
/**
* If run as a requestAnimationFrame callback, this
* will be run at the start of the frame.
*/
function updateScreen(time) {
// Make visual updates here.
}
requestAnimationFrame(updateScreen);
框架或示例可以使用 setTimeout
或 setInterval
来执行视觉更改,例如动画、
但这种方法的问题在于,回调将在帧中的某个时间点运行,可能是
这种情况通常会导致我们遗漏一帧,进而导致卡顿。
![setTimeout 导致浏览器丢失帧。](https://web.developers.google.cn/static/articles/optimize-javascript-execution/image/settimeout-causing-brows-6424030c04e02.jpg?authuser=9&hl=lv)
事实上,jQuery 过去使用 setTimeout
来实现其 animate
行为。它已更改为使用
requestAnimationFrame
(在版本 3 中)。
如果您使用的是旧版 jQuery
进行修补以使用 requestAnimationFrame
,
强烈建议您这样做
降低复杂性或使用 Web Worker
JavaScript 在浏览器的主线程上运行,与样式计算、布局以及 在许多情况下绘制如果您的 JavaScript 运行了很长时间,就会阻止这些其他任务, 可能会导致帧丢失
您应该灵活管理 JavaScript 的运行时间和运行时长。例如,如果您在 滚动之类的动画效果时,最好是想办法让 JavaScript 保持在 3-4 毫秒。如果超过这个时间,就可能占用太多时间。设备处于闲置状态时 那么对于所花费的时间,您可以更放松一些。
在许多情况下,可以将纯粹的计算工作 Web Workers, 。数据操纵或遍历 通常非常适合此模型。
var dataSortWorker = new Worker("sort-worker.js");
dataSortWorker.postMesssage(dataToSort);
// The main thread is now free to continue working on other things...
dataSortWorker.addEventListener('message', function(evt) {
var sortedData = evt.data;
// Update data on screen...
});
并非所有工作都适合这种模型:Web Worker 没有 DOM 访问权限。如果您的工作必须在主线程上完成,请考虑采用批处理方法,将较大的任务细分为多个微任务,每个微任务用时不超过几毫秒,并在每一帧的 requestAnimationFrame
处理程序中运行。
这种方法会对用户体验和界面产生影响,您需要确保用户知道 通过使用进度或活动指示器来表示正在处理任务。 在任何情况下,这种方法都能让应用的主线程处于空闲状态,从而帮助其保持对 用户互动
了解 JavaScript 的“帧税”
在评估框架、库或您自己的代码时,务必要评估 逐帧运行 JavaScript 代码所需的费用。这是 在执行对性能至关重要的动画工作(例如 过渡或滚动效果
Chrome DevTools 的“Performance”面板是衡量 JavaScript 的费用。通常,您会获得如下低级记录:
![在 Chrome 开发者工具中记录性能](https://web.developers.google.cn/static/articles/optimize-javascript-execution/image/a-performance-recording-ed012f2de06f6.png?authuser=9&hl=lv)
主要部分提供了 JavaScript 调用的火焰图,让您可以 可以准确地分析调用了哪些函数以及每个函数花费的时间。
有了这些信息,您就可以评估 JavaScript,并开始查找并修复 函数的执行时间过长。如前所述, 移除长时间运行的 JavaScript;如果无法移除, 从而释放主线程以继续处理其他任务。
请参阅开始分析运行时性能,了解如何使用 “性能”面板
避免微优化 JavaScript
知道浏览器执行某一版本的速度比执行版本快 100 倍可能很酷。
比方说,请求元素的 offsetTop
比
getBoundingClientRect()
,但几乎总是这样,您只会调用如下函数:
因此在每帧中只处理很少次数,所以将精力通常浪费在这方面的工作上
JavaScript 的性能。您通常只能节省零点几毫秒的时间。
如果您正在开发游戏或计算成本高昂的应用,那么您可能属于例外情况, 因为您通常需要在单个帧中放置大量计算,并且 这样的话,一切都可以派上用场。
简而言之,您应对微优化非常谨慎,因为它们通常不会映射到 您正在构建的应用