--- title: Waterfall slug: Tools/Performance/Waterfall translation_of: Tools/Performance/Waterfall ---
通过瀑布流,您可以了解浏览器在运行网站或应用程序时所做的各种事情。它的基础是浏览器在运行网站时所做的事情可以分为各种类型 - 运行 JavaScript,更新布局等等 - 而且在任何时候,浏览器都在做这些事情之一。
因此,如果您看到性能问题的迹象 - 例如帧速下降,您可以前往瀑布流查看浏览器在录制过程中正在进行的操作。
沿着 X 轴是时间。记录的操作(称为标记)显示为水平条,以瀑布流形式显示,以反映浏览器执行的连续性。
选择标记后,您会在右侧的侧边栏中看到更多关于它的信息。这包括标记的持续时间以及特定于标记类型的更多信息。
操作标记用颜色标记和标记。记录下列操作:
名称和说明 | 颜色 | 详细资料 |
---|---|---|
为响应 DOM 事件而执行的 JavaScript 代码。 |
|
|
在页面中执行的 JavaScript 函数标有该函数被调用的原因: 脚本标记 |
|
|
解析 HTML 花费时间解析页面的 HTML。 |
|
|
解析 XML 花费时间解析页面的 XML。 |
|
|
重新计算样式 计算适用于页面元素的计算样式。 |
|
|
布局 计算页面元素的位置和大小。该操作有时称为“回流”。 |
||
绘制 将像素绘制到屏幕上。 |
||
垃圾回收 垃圾回收事件。非增量 GC 事件标记为“(非增量)”。 |
Firefox 46 中的新增功能:如果GC 事件是由分配压力引起的,则会显示一个链接,标记为“显示分配触发器”。点击链接可查看导致此 GC 事件的分配配置文件。 有关更多详细信息,请参阅分配和垃圾收集。 |
|
周期回收 回收 C ++ 引用计数的数据结构。 像垃圾回收一样,但是用于C ++对象。请参阅 Kyle Huey 关于周期收集的博客文章。 |
|
|
CC 图减少 循环回收的准备/预优化。 |
|
|
控制台 匹配 |
||
时间戳 |
|
|
DOMContentLoaded 文档的 |
||
加载 文档的 |
||
主线程中的 worker 事件 主线程向 worker 发送消息或从 worker 接收消息时显示。 |
之一:
|
|
worker 线程中的 worker 事件 当 worker 从主线程收到消息或向主线程发送消息时显示。 |
之一:
|
瀑布流工具中的标记及其颜色与瀑布流概述中的相同,因此可以很容易地从一个到另一个进行关联。
您可以使用工具栏中的按钮控制显示哪些标记:
您在瀑布流中看到的内容完全取决于您的网站所做的事情:JavaScript 网站会有很多橙色,而视觉动态网站会有很多紫色和绿色。但有一些常见的模式可以提醒您可能出现的性能问题。
您在瀑布流视图中经常会看到的一种模式如下所示:
这是浏览器用于响应某些事件更新页面的基本算法的可视化:
该顺序需要匹配一帧,因为屏幕在完成之前不会更新。人们普遍接受每秒60帧是动画显示平滑的速率。对于每秒60帧的速率,浏览器会以16.7毫秒的时间执行完整的流程。
重要的是响应能力,浏览器并不总是执行每一步:
width
,display
,font-size
,或 top
,将引起回流。但是,修改不会改变几何或位置的属性,例如 color
或 opacity
不会。transform
属性为元素设置动画效果,则浏览器将为已转换的元素使用单独的图层,并且在元素移动时甚至不必重绘:元素的新位置在组合中处理。该动画效果的 CSS 属性介绍了如何为不同的CSS属性设置动画进而赋予不同的性能结果,与瀑布流如何能够帮助发出信号。
默认情况下,站点的 JavaScript 在与浏览器用于布局更新,重绘,DOM 事件等相同的线程中执行。这意味着长时间运行的 JavaScript 函数可能会导致无响应(无效):动画可能不平滑,或者该网站甚至可能会冻结。
同时使用帧速率工具和瀑布流,很容易看到长时间运行的 JavaScript 引起响应问题的时间。在下面的屏幕截图中,我们放大了导致帧频下降的 JS 函数:
在密集的 JavaScript 文章显示了瀑布流如何突出造成长期的 JavaScript 函数响应的问题,以及如何使用异步方法来保持主线程响应。
某些绘画效果(例如 box-shadow
)可能很昂贵,尤其是在浏览器必须在每一帧中计算它们的过渡中应用它们时。如果您看到帧频下降,尤其是在图形密集型操作和转换期间,请检查瀑布流是否有长绿色标记。
瀑布流中的红色标记表示垃圾回收(GC)事件,其中 SpiderMonkey (Firefox 中的 JavaScript 引擎)遍历堆寻找不再可及的内存并随后释放它。GC 与性能相关,因为它在运行时必须暂停 JavaScript 引擎,以便程序暂停并且完全无响应。
为了减少暂停的时间,SpiderMonkey 实现了增量 GC:这意味着它可以以相当小的增量执行垃圾回收,让程序在两者之间运行。但有时候,它需要执行完整的非增量回收,程序必须等待它完成。
在试图避免 GC 事件,尤其是非增量 GC 事件时,明智的做法是不尝试针对JavaScript 引擎的特定实现进行优化。SpiderMonkey 使用一套复杂的启发式方法来确定何时需要 GC,何时需要非增量 GC。一般来说,虽然:
当瀑布流记录 GC 标记时,它表示:
两个标记直接由控制台 API 调用控制:“控制台”和“时间戳”。
这些使您可以标记录制的特定部分。
要制作控制台标记,请在该部分的开始处调用console.time()
结尾处调用console.timeEnd()
。这些函数带有一个用于命名该部分的参数。
例如,假设我们有这样的代码:
var iterations = 70; var multiplier = 1000000000; function calculatePrimes() { console.time("calculating..."); var primes = []; for (var i = 0; i < iterations; i++) { var candidate = i * (multiplier * Math.random()); var isPrime = true; for (var c = 2; c <= Math.sqrt(candidate); ++c) { if (candidate % c === 0) { // not prime isPrime = false; break; } } if (isPrime) { primes.push(candidate); } } console.timeEnd("calculating..."); return primes; }
瀑布流的输出将如下所示:
标记用您传递给的参数 console.time()
进行标记,当您选择标记时,可以在右侧边栏中看到程序堆栈。
Firefox 中的新功能41。
从 Firefox 41 开始,右侧侧边栏也会在结尾显示堆栈:即在 console.timeEnd()
被调用时。如果 console.timeEnd()
从 a 的解析中被调用 Promise
,它也会显示“(Async:Promise)”,在这个下面它将显示“异步堆栈”:也就是说,在承诺的地方调用堆栈。
例如,考虑这样的代码:
var timerButton = document.getElementById("timer"); timerButton.addEventListener("click", handleClick, false); function handleClick() { console.time("timer"); runTimer(1000).then(timerFinished); } function timerFinished() { console.timeEnd("timer"); console.log("ready!"); } function runTimer(t) { return new Promise(function(resolve) { setTimeout(resolve, t); }); }
瀑布流将显示一个标志物之间的期间 time()
和 timeEnd()
,如果你选择它,你会看到侧边栏的异步栈:
时间戳使您可以在录制中标记一个瞬间。
要制作时间戳记标记,请调用 console.timeStamp()
。您可以传递参数来标记时间戳。
例如,假设我们调整上面的代码以每循环 10 次迭代一次时间戳,并用迭代号标记:
var iterations = 70; var multiplier = 1000000000; function calculatePrimes() { console.time("calculating..."); var primes = []; for (var i = 0; i < iterations; i++) { if (i % 10 == 0) { console.timeStamp(i.toString()); } var candidate = i * (multiplier * Math.random()); var isPrime = true; for (var c = 2; c <= Math.sqrt(candidate); ++c) { if (candidate % c === 0) { // not prime isPrime = false; break; } } if (isPrime) { primes.push(candidate); } } console.timeEnd("calculating..."); return primes; }
在瀑布现在你会看到这样的东西: