likes
comments
collection
share

[译] scheduler.yield 性能优化 API

作者站长头像
站长
· 阅读数 18

原文链接: nitropack.io/blog/post/i…

原文作者:Niko Kaleev

如何测试scheduler.yield():优化INP的Chrome API

TL;DR: Chrome的scheduler.yield() API承诺通过允许开发人员更好地管理任务执行来彻底改变网站的响应性,确保更平滑的用户交互和改进的下一次绘制(INP)得分。这种方法提供了一个实用的解决方案,可以分解长时间的任务,而不会出现现有方法的缺点,旨在实现任务管理和用户体验之间的最佳平衡。

毫无疑问,Google在2023年全力以赴提高响应性。

到目前为止,他们已经:

  • Interaction to Next Paint从实验性移至待定状态;
  • 宣布INP将在2024年3月取代第一次输入延迟,成为响应性的新核心Web Vital指标;
  • 开始在搜索控制台中标记INP问题,并向未达到良好响应阈值的网站发送电子邮件;
  • 在2024年3月12日,INP正式取代FID成为新的响应性度量标准。

现在,Chrome团队宣布他们目前正在进行一个新的调度器API——scheduler.yield()的起源试验。

预计scheduler.yield()将帮助开发人员通过提供更简单、更好的方式将控制权返还给主线程来改进其网站的响应性。

继续阅读以了解更多关于新API以及如何在您的网站上尝试它的信息。

关于长任务和主线程的简要回顾

如果您对长任务和主线程非常了解,请随意跳过这部分内容。如果不了解,请阅读这个简要回顾,因为它对于理解scheduler.yield()以及如何实现它至关重要。

浏览器所做的所有工作都被视为任务。这包括渲染、解析HTML和CSS、运行您编写的JavaScript代码以及您可能无法直接控制的其他内容。

主线程是浏览器完成大部分工作的地方。

[译] scheduler.yield 性能优化 API

不幸的是,主线程一次只能处理一个任务。如果一个任务运行时间超过50毫秒,它就被视为长任务。

遇到长任务意味着浏览器将运行它,直到完成为止。完成后,控制权将返回给主线程,允许浏览器处理队列中的下一个任务。

长任务是页面响应性差的主要原因,因为它们延迟了浏览器响应用户输入的能力。此外,JavaScript以其“运行至完成”模型是阻塞主线程的主要原因。

这就是为什么它被视为渲染阻塞资源 - 当浏览器遇到它时,必须在执行任何其他操作之前下载、解析和执行它。

好消息是,只是因为您的代码在浏览器中启动了一个任务,并不意味着您必须等到该任务完成后才将控制权返回给主线程。

[译] scheduler.yield 性能优化 API

您可以通过在任务中明确地让步来分解长任务。

简而言之,任务让步确保浏览器不会因为一个任务而忽略或延迟响应其他重要任务或用户交互。

[译] scheduler.yield 性能优化 API

不幸的是,当前的让步策略并不完美…

为什么使用scheduler.yield():当前让步策略存在的问题

向主线程让步并不是一个新概念。开发人员已经使用不同的让步策略相当长的一段时间来分解长任务:

1. setTimeout()

setTimeout()允许您安排一个任务在指定的延迟后运行,或者定期运行。即使您指定了超时为0,这也会将回调的执行推迟到单独的任务中。当您有多个应该按顺序运行的函数时,此方法非常有效。

缺点: 不保证精确性。由于队列中的其他任务,回调可能不会在指定的延迟后立即运行。此外,如果在循环中处理大量数据集,任务可能会变得耗时,特别是在有数百万条目的情况下。

2. requestIdleCallback()

requestIdleCallback()允许您安排在浏览器可能有的任何空闲期间运行任务。它非常适用于执行非紧急任务而不影响用户体验。

缺点: requestIdleCallback()以最低可能的优先级安排任务,这意味着如果主线程拥挤,预定的任务可能永远不会运行。

3. isInputPending()

isInputPending() 可以随时执行,以检查用户是否正在尝试与页面上的元素交互。如果是,则该函数返回 true ;如果不是,则返回 false

想象一下,您有一系列要执行的任务,但不想干扰用户交互。您可以使用 isInputPending() 和 yieldToMain() 函数来确保用户输入在与页面交互时不会延迟。

缺点: isInputPending() 并不总是在用户输入后立即返回 true。这是因为操作系统需要一段时间来告诉浏览器交互发生了。这意味着其他代码可能已经开始执行。

这些是回到主线程的一些常用方法。正如您所见,每种方法都有自己的缺点。

但最大的缺点是:

当您通过将代码推迟到后续任务中运行而让步给主线程时,该代码将被添加到任务队列的末尾。

为什么这是一个问题?

答案有三个方面:

  • 逻辑错误的增加: 由于推迟的代码被放置在任务队列的末尾,可能会有其他任务在浏览器返回到推迟的任务之前执行。这可能会影响函数执行的顺序,导致逻辑错误或意外行为。

  • 执行延迟: 如果队列中有许多任务,则在浏览器到达并执行推迟的代码之前可能需要相当长的时间。

  • 不可预测性: 很难准确预测推迟的任务将在何时运行,因为它取决于队列中已有任务的数量和性质。这种不可预测性可能会使调试和性能优化变得困难。

总之,虽然使用当前策略将代码推迟到主线程可以帮助保持响应性用户界面,但也可能会在确保代码及时有序执行方面带来挑战。

介绍 scheduler.yield()

对于 Chrome 正在运行 scheduler.yield() 的原始试验 的兴奋之处在于,它是一个调度器 API,解决了其他让步策略的所有缺点。

除此之外,这是一个解决方案,可以让开发人员和网站所有者都能够实现响应式网站和良好的 INP 分数,同时无缝执行其余的代码。

那么,为什么对于 scheduler.yield()_ 会引起这么大的兴奋呢?_

首先,scheduler.yield() 是一个专门的让步函数。例如,setTimeout() 用于分解长任务并让步给主线程,但它更像是一个函数副作用,而不是一个默认选项。

其次,scheduler.yield() 将剩余的工作发送到队列的前面。这意味着您希望在让步后立即恢复的工作不会因其他来源的任务而被搁置。

简而言之:

scheduler.yield() 给您带来了两全其美的选择——您可以让步以改善网站的响应性和 INP 分数,并确保您希望在让步后完成的工作不会延迟。

“重构长任务并不总是直截了当的。Chrome 团队提供了一种人性化的方式来实现这一点,这绝对是朝着正确方向迈出的一步。”Ivailo Hristov,NitroPack 的 CTO。

如何尝试新的调度器 API

从 Chrome 115 开始,您可以自行测试 scheduler.yield。

要尝试新的 API,只需按照 Google 的说明进行操作:

  1. 如果您想在本地尝试 scheduler.yield,请在 Chrome 的地址栏中输入 chrome://flags,然后在“实验性网络平台功能”部分的下拉菜单中选择“启用”。这将使 scheduler.yield(以及任何其他实验性功能)仅在您的 Chrome 实例中可用。

  2. 如果您想为真实的 Chromium 用户在公开可访问的源上启用 scheduler.yield,则需要注册 scheduler.yield 源试验。这使您可以安全地在一定时间内尝试提议的功能,并为 Chrome 团队提供有关这些功能在现场使用情况的宝贵见解。有关源试验的更多信息,请阅读此指南

一旦您进行了测试,您还可以提供反馈意见,说明如何改进。

安全测试!

转载自:https://juejin.cn/post/7371995232161529856
评论
请登录