Debounce 您的输入处理程序

输入处理程序是您的应用中潜在的性能问题原因,因为它们会阻止帧完成,并可能导致额外的和不必要的布局工作。

输入处理程序是您的应用中潜在的性能问题原因,因为它们会阻止帧完成,并可能导致额外的和不必要的布局工作。

摘要

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

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

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

Lightweight scrolling; compositor only.

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

Heavy scrolling; compositor is blocked on JavaScript.

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

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

输入处理程序(如滚动和触摸的处理程序)被安排在任何 requestAnimationFrame 回调之前运行。

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

Heavy scrolling; compositor is blocked on JavaScript.

Debounce 您的滚动处理程序

上述两个问题的解决方案是相同的:您应该始终 debounce 视觉更改到下一个 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);

这样做还具有额外的优势,即保持输入处理程序的轻量,这非常棒,因为现在您不会在计算密集型代码上阻止诸如滚动或触摸之类的操作!