使输入处理程序去除抖动

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

Paul Lewis

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

摘要

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

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

在最快的情况下,当用户与网页互动时,网页的 compositor 线程可以接收用户的触摸输入,然后只需移动内容即可。这不需要主线程执行任何工作,主线程负责执行 JavaScript、布局、样式或绘制操作。

轻量级滚动;仅限 compositor。

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

滚动速度缓慢;JavaScript 阻塞了 compositor。

简而言之,您应确保运行的所有输入处理脚本都应快速执行,并允许 compositor 执行其工作。

避免在输入处理脚本中更改样式

输入处理脚本(例如滚动和触摸处理脚本)会安排在任何 requestAnimationFrame 回调之前运行。

如果您在其中一个处理脚本中进行视觉更改,则在 requestAnimationFrame 开始时,系统会显示待处理的样式更改。如果您随后在 requestAnimationFrame 回调开始时读取视觉属性,则会触发强制同步布局,如“避免大型复杂布局和布局抖动”中的建议所述。

滚动速度缓慢;JavaScript 阻塞了 compositor。

对滚动处理程序进行去抖动

上述两个问题的解决方法相同:您应始终对下一个 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);

这样做还有一个额外的好处,就是可以让输入处理程序保持轻量级,这非常棒,因为现在您不会因计算量大的代码而阻塞滚动或轻触等操作!