使输入处理程序去除抖动

输入处理程序可能是应用出现性能问题的原因,因为它们可能阻止帧完成,并且可能导致额外(且不必要)的布局工作。

Paul Lewis

输入处理程序可能是应用出现性能问题的原因, 它们可能会阻止帧完成,并可能导致额外 布局工作。

摘要

  • 避免长时间运行的输入处理程序;它们会阻止滚动。
  • 不要在输入处理程序中进行样式更改。
  • 使处理程序去除抖动;存储事件值并在下一个 requestAnimationFrame 回调中处理样式更改。

避免长时间运行的输入处理程序

在最快的情况下,当用户与页面交互时,页面的合成器线程可以获取用户的触摸输入并直接移动内容。这不需要主线程执行任何工作,主线程中负责执行 JavaScript、布局、样式或绘制。

轻量级滚动;合成器。

不过,如果您附加了输入处理程序(如 touchstarttouchmovetouchend),则合成器线程必须等待此处理程序执行完毕,因为您可以选择调用 preventDefault() 并阻止触摸滚动发生。即使您不调用 preventDefault(),合成器也必须等待,因此用户的滚动操作会被阻止,这可能会导致卡顿和丢帧。

大量滚动;合成器在 JavaScript 上被屏蔽。

简而言之,您应确保所运行的任何输入处理程序都应快速执行,并允许合成器完成其工作。

避免在输入处理程序中更改样式

与滚动和触摸的处理程序一样,输入处理程序会被安排在任何 requestAnimationFrame 回调之前运行。

如果您在其中一个处理程序内进行了视觉更改,则在 requestAnimationFrame 开始时,将有待处理的样式更改。如果您然后在 requestAnimationFrame 回调开始时读取视觉属性(如“避免大型、复杂的布局和布局抖动”中的建议所述),您将触发强制同步布局!

大量滚动;合成器在 JavaScript 上被屏蔽。

使滚动处理程序去除抖动

上述两个问题的解决方案都是相同的:您应始终让下一个 requestAnimationFrame 回调的视觉更改去除抖动:

function onScroll (evt) {

    // Store the scroll value for laterz.
    lastScrollY = window.scrollY;

    // Prevent multiple rAF callbacks.
    if (scheduledAnimationFrame)
    return;

    scheduledAnimationFrame = true;
    requestAnimationFrame(readAndUpdatePage);
}

window.addEventListener('scroll', onScroll);

这样做还有另外一个好处,即让输入处理程序保持轻巧。这太棒了,因为现在您不用在计算开销大的代码上阻止滚动或触摸等操作!