Javascript OnScroll 性能比较
Javascript OnScroll performance comparison
Update:类似的问题有一个很好的答案,展示了如何以有用的方式使用带有滚动的 requestAnimationFrame:
假设我想在我的网站上添加一些由滚动触发的昂贵操作。例如,我在我的 jsfiddle 中使用了视差效果。
现在我一直在读它一定不能直接绑定到事件上,有时后面跟着一些片段是为了更好。举几个例子:
- Attaching JavaScript Handlers to Scroll Events = BAD!
- How to develop high performance onScroll event?
- How to make faster scroll effects?
- 60FPS onscroll event listener
他们说的基本上是不要这样做:
// Bad guy 1
$(window).scroll( function() {
animate(ex1);
});
或这个
// Bad guy 2
window.addEventListener('scroll', onScroll, false);
function onScroll() {
animate(ex2);
}
但是使用超时、间隔、requestAnimationFrame 等等,例如:
// Good guy
$(window).scroll( function() {
scrolling1 = true;
});
setInterval( function() {
if (scrolling1) {
scrolling1 = false;
animate(ex3);
}
}, 50 );
所以,我将在上面的链接中找到的选项添加到一个 jsfiddle,该 jsfiddle 试图通过为每种方法添加一个计数器来比较它们,如下所示:
// Test
$(window).scroll( function() {
counter = counter + 1;
// output result of counter
animate(ex1);
});
最好检查完整jsfiddle
结果:凡事顺利,计算次数差不多。如果我能忍受波涛汹涌的影响,也许我可以保护一些资源。与我阅读的所有内容相比,这对我来说似乎合乎逻辑!
第一题:
我错过了什么或者这是一个有效的测试吗?如果它无效,我怎么能正确测试?
编辑:澄清一下,我想测试以上任何方法是否完全节省性能。
第二个问题:
如果有效,为什么每个人都对 onscroll 感到紧张?如果流体动画需要在整个站点上进行 5000 次计算,那么无论如何都无法更改?
(好吧,有时我会使用检查来确定对象是否在视口中,但老实说,我什至不知道这些检查是否不如被阻止的代码本身昂贵,尤其是如果它们涉及五个不同的变量,例如 offset、windowHeight、scrolltTop、getBoundingClientRect 和 outerHeight...)
我不确定我是否正确理解了你的问题和所有陈述,但我会尽力给你一个答案:
- 我是不是遗漏了什么或者这是一个有效的测试?如果无效,我怎么测试正确?
如果您测量函数被调用的次数,这是一个有效的测试,这当然取决于浏览器,因此,GPU 是否增强以及您在您的评论中评论的其他一些基准参数已经提问了。
如果我们认为测量是正确的,那么可以说通过使用超时或 requestAnimationFramework 可以 节省时间,因为我们基本上遵循 debouncing or throttling. Basically we do not want to request or called a function more times than is needed. In the case of the timer we will queue less functions calls and in the case of requestAnimationFrame 的原则,因为它在重新绘制之前排队调用并将按顺序执行它们。在超时中,如果它们非常重,可能会发生计算重叠。
我在 中找到了更好的答案,解释了浏览器中动画的主要问题,如剪切、闪烁或跳帧。它还包括一个很好的演示。
我认为你的测试方法是正确的,你也应该正确解释它,因为你的硬件和你的引擎可能调用接近相同的数字,但正如所说,去抖动和节流是一种性能缓解。
Here also one more article supporting not attach handlers to window scroll from Twitter。 (免责声明:本文来自 2011 年,浏览器以不同方式处理滚动优化)。
- 为什么大家都对onscroll感到紧张?如果流体动画需要在整个站点上进行 5000 次计算,那么无论如何都无法更改吗?
我不认为性能下降会让人紧张,但用户体验会因为上面提到的过度调用滚动可能导致的动画问题而变得最差,或者即使你的计时器不同步你也可以仍然遇到相同的 'performance' 问题。人们只是建议将调用保存为滚动,因为:
人类视觉持久性不需要超高帧率,因此尝试更频繁地显示图像是没有用的。
对于更复杂的计算或繁重的动画,浏览器已经在进行优化,就像您检查过的那样,与 2、3 或 6 年前您公开的文章相比,有些browsers had optimize this things。
所以,@SirPeople 已经正确回答了你的第一个问题,查看 animate 函数被调用的频率确实是一个很好的测试,但是比较不同片段的性能是一个糟糕的测试。
这是执行的性能记录:
函数 animate
一点都不昂贵。我拍摄了一个性能记录(下一张图片),它显示在我查看的一次迭代中它花费了 0.64 毫秒到 1.29 毫秒(第 1-5 点)。而且一旦功能完成,重绘根本不需要时间(第 6 点),这可能是因为页面几乎没有内容。当我们看一下时间,我们可以看到所有五个动画函数和重绘都发生在不到 10 毫秒的时间内,这在正常情况下意味着我们可以获得流畅的 60fps 动画(第 7 点)。
此外,如果我们想要比较 onscroll 事件侦听器,我们需要单独测试每个侦听器并比较结果。如果其中一个侦听器真的被阻止,它将对整个页面产生影响,如果不进行性能调试,您将不知道它是哪个。
我制作了两个 jsfiddle window.scroll and RAF。而且,令我惊讶的是,似乎没有任何区别。
人们为什么关注这个?
正如您在上面链接的 jsfiddles 中看到的那样,如果事件处理程序变得太大,整个 页面将会滞后。
现在怎么办?
我自己并不是性能大师,但是:
- 也许其他解决方案之一是正确的
- 我们可以将您的事件侦听器标记为被动,尽管在我的 test 中它并没有真正改善
https://developers.google.com/web/updates/2016/06/passive-event-listeners
- 我们可以通过移除视差效果来优化事件侦听器
- 还有一个叫做 Intersection Observer 的新东西应该会快很多,我没测试过
https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
Update:类似的问题有一个很好的答案,展示了如何以有用的方式使用带有滚动的 requestAnimationFrame:
假设我想在我的网站上添加一些由滚动触发的昂贵操作。例如,我在我的 jsfiddle 中使用了视差效果。
现在我一直在读它一定不能直接绑定到事件上,有时后面跟着一些片段是为了更好。举几个例子:
- Attaching JavaScript Handlers to Scroll Events = BAD!
- How to develop high performance onScroll event?
- How to make faster scroll effects?
- 60FPS onscroll event listener
他们说的基本上是不要这样做:
// Bad guy 1
$(window).scroll( function() {
animate(ex1);
});
或这个
// Bad guy 2
window.addEventListener('scroll', onScroll, false);
function onScroll() {
animate(ex2);
}
但是使用超时、间隔、requestAnimationFrame 等等,例如:
// Good guy
$(window).scroll( function() {
scrolling1 = true;
});
setInterval( function() {
if (scrolling1) {
scrolling1 = false;
animate(ex3);
}
}, 50 );
所以,我将在上面的链接中找到的选项添加到一个 jsfiddle,该 jsfiddle 试图通过为每种方法添加一个计数器来比较它们,如下所示:
// Test
$(window).scroll( function() {
counter = counter + 1;
// output result of counter
animate(ex1);
});
最好检查完整jsfiddle
结果:凡事顺利,计算次数差不多。如果我能忍受波涛汹涌的影响,也许我可以保护一些资源。与我阅读的所有内容相比,这对我来说似乎合乎逻辑!
第一题: 我错过了什么或者这是一个有效的测试吗?如果它无效,我怎么能正确测试? 编辑:澄清一下,我想测试以上任何方法是否完全节省性能。
第二个问题: 如果有效,为什么每个人都对 onscroll 感到紧张?如果流体动画需要在整个站点上进行 5000 次计算,那么无论如何都无法更改?
(好吧,有时我会使用检查来确定对象是否在视口中,但老实说,我什至不知道这些检查是否不如被阻止的代码本身昂贵,尤其是如果它们涉及五个不同的变量,例如 offset、windowHeight、scrolltTop、getBoundingClientRect 和 outerHeight...)
我不确定我是否正确理解了你的问题和所有陈述,但我会尽力给你一个答案:
- 我是不是遗漏了什么或者这是一个有效的测试?如果无效,我怎么测试正确?
如果您测量函数被调用的次数,这是一个有效的测试,这当然取决于浏览器,因此,GPU 是否增强以及您在您的评论中评论的其他一些基准参数已经提问了。
如果我们认为测量是正确的,那么可以说通过使用超时或 requestAnimationFramework 可以 节省时间,因为我们基本上遵循 debouncing or throttling. Basically we do not want to request or called a function more times than is needed. In the case of the timer we will queue less functions calls and in the case of requestAnimationFrame 的原则,因为它在重新绘制之前排队调用并将按顺序执行它们。在超时中,如果它们非常重,可能会发生计算重叠。
我在
我认为你的测试方法是正确的,你也应该正确解释它,因为你的硬件和你的引擎可能调用接近相同的数字,但正如所说,去抖动和节流是一种性能缓解。
Here also one more article supporting not attach handlers to window scroll from Twitter。 (免责声明:本文来自 2011 年,浏览器以不同方式处理滚动优化)。
- 为什么大家都对onscroll感到紧张?如果流体动画需要在整个站点上进行 5000 次计算,那么无论如何都无法更改吗?
我不认为性能下降会让人紧张,但用户体验会因为上面提到的过度调用滚动可能导致的动画问题而变得最差,或者即使你的计时器不同步你也可以仍然遇到相同的 'performance' 问题。人们只是建议将调用保存为滚动,因为: 人类视觉持久性不需要超高帧率,因此尝试更频繁地显示图像是没有用的。 对于更复杂的计算或繁重的动画,浏览器已经在进行优化,就像您检查过的那样,与 2、3 或 6 年前您公开的文章相比,有些browsers had optimize this things。
所以,@SirPeople 已经正确回答了你的第一个问题,查看 animate 函数被调用的频率确实是一个很好的测试,但是比较不同片段的性能是一个糟糕的测试。
这是执行的性能记录:
函数 animate
一点都不昂贵。我拍摄了一个性能记录(下一张图片),它显示在我查看的一次迭代中它花费了 0.64 毫秒到 1.29 毫秒(第 1-5 点)。而且一旦功能完成,重绘根本不需要时间(第 6 点),这可能是因为页面几乎没有内容。当我们看一下时间,我们可以看到所有五个动画函数和重绘都发生在不到 10 毫秒的时间内,这在正常情况下意味着我们可以获得流畅的 60fps 动画(第 7 点)。
此外,如果我们想要比较 onscroll 事件侦听器,我们需要单独测试每个侦听器并比较结果。如果其中一个侦听器真的被阻止,它将对整个页面产生影响,如果不进行性能调试,您将不知道它是哪个。
我制作了两个 jsfiddle window.scroll and RAF。而且,令我惊讶的是,似乎没有任何区别。
人们为什么关注这个?
正如您在上面链接的 jsfiddles 中看到的那样,如果事件处理程序变得太大,整个 页面将会滞后。
现在怎么办?
我自己并不是性能大师,但是:
- 也许其他解决方案之一是正确的
- 我们可以将您的事件侦听器标记为被动,尽管在我的 test 中它并没有真正改善 https://developers.google.com/web/updates/2016/06/passive-event-listeners
- 我们可以通过移除视差效果来优化事件侦听器
- 还有一个叫做 Intersection Observer 的新东西应该会快很多,我没测试过 https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API