Waterfall - Firefox 开发者工具 编辑
通过瀑布流,您可以了解浏览器在运行网站或应用程序时所做的各种事情。它的基础是浏览器在运行网站时所做的事情可以分为各种类型 - 运行 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 网站会有很多橙色,而视觉动态网站会有很多紫色和绿色。但有一些常见的模式可以提醒您可能出现的性能问题。
渲染瀑布流
您在瀑布流视图中经常会看到的一种模式如下所示:
这是浏览器用于响应某些事件更新页面的基本算法的可视化:
- JavaScript 函数调用:某些事件(例如 DOM 事件)会导致页面中的某些JavaScript 运行。JavaScript 改变了页面的一些 DOM 或 CSSOM。
- 重新计算样式:如果浏览器认为页面元素的计算样式已更改,则必须重新计算它们。
- 布局:接下来,浏览器使用计算的样式来确定元素的位置和几何形状。此操作被标记为“布局”,但有时也称为“回流”。
- Paint:最后,浏览器需要重新绘制元素到屏幕上。最后一步不是按照这个顺序显示的:页面可以分成多个图层,这些图层被独立绘制,然后在称为“组合”的过程中合并。
该顺序需要匹配一帧,因为屏幕在完成之前不会更新。人们普遍接受每秒60帧是动画显示平滑的速率。对于每秒60帧的速率,浏览器会以16.7毫秒的时间执行完整的流程。
重要的是响应能力,浏览器并不总是执行每一步:
- CSS 动画 更新页面,而无需运行任何 JavaScript。
- 并非所有的 CSS 属性更改都会导致重排。修改可以改变对象的几何形状和位置的属性,例如
width
,display
,font-size
,或top
,将引起回流。但是,修改不会改变几何或位置的属性,例如color
或opacity
不会。 - 并非所有 CSS 属性更改都会导致重新绘制。特别是,如果使用该
transform
属性为元素设置动画效果,则浏览器将为已转换的元素使用单独的图层,并且在元素移动时甚至不必重绘:元素的新位置在组合中处理。
该动画效果的 CSS 属性介绍了如何为不同的CSS属性设置动画进而赋予不同的性能结果,与瀑布流如何能够帮助发出信号。
阻塞 JavaScript
默认情况下,站点的 JavaScript 在与浏览器用于布局更新,重绘,DOM 事件等相同的线程中执行。这意味着长时间运行的 JavaScript 函数可能会导致无响应(无效):动画可能不平滑,或者该网站甚至可能会冻结。
同时使用帧速率工具和瀑布流,很容易看到长时间运行的 JavaScript 引起响应问题的时间。在下面的屏幕截图中,我们放大了导致帧频下降的 JS 函数:
在密集的 JavaScript 文章显示了瀑布流如何突出造成长期的 JavaScript 函数响应的问题,以及如何使用异步方法来保持主线程响应。
昂贵的绘制
某些绘画效果(例如 box-shadow
)可能很昂贵,尤其是在浏览器必须在每一帧中计算它们的过渡中应用它们时。如果您看到帧频下降,尤其是在图形密集型操作和转换期间,请检查瀑布流是否有长绿色标记。
垃圾回收
瀑布流中的红色标记表示垃圾回收(GC)事件,其中 SpiderMonkey (Firefox 中的 JavaScript 引擎)遍历堆寻找不再可及的内存并随后释放它。GC 与性能相关,因为它在运行时必须暂停 JavaScript 引擎,以便程序暂停并且完全无响应。
为了减少暂停的时间,SpiderMonkey 实现了增量 GC:这意味着它可以以相当小的增量执行垃圾回收,让程序在两者之间运行。但有时候,它需要执行完整的非增量回收,程序必须等待它完成。
在试图避免 GC 事件,尤其是非增量 GC 事件时,明智的做法是不尝试针对JavaScript 引擎的特定实现进行优化。SpiderMonkey 使用一套复杂的启发式方法来确定何时需要 GC,何时需要非增量 GC。一般来说,虽然:
- GC 在分配大量内存时需要
- 当内存分配速率足够高以至于 SpiderMonkey 在增量GC期间可能会耗尽内存时,通常需要非增量GC
当瀑布流记录 GC 标记时,它表示:
- GC 是否是增量式的
- GC 执行的原因
- 如果 GC 是非递增的,则它是非递增的原因
- 从 Firefox 46 开始,如果 GC 事件是由分配压力引起的,则会显示一个链接,标记为“显示分配触发器”。点击链接可查看导致此 GC 事件的分配配置文件。有关更多详细信息,请参阅分配和垃圾回收。
使用控制台 API 添加标记
两个标记直接由控制台 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;
}
在瀑布现在你会看到这样的东西:
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论