写点什么

释放浏览器潜力:Web Scheduler 背后的系统性能提升

作者:。。。
  • 2023-10-27
    广东
  • 本文字数:6243 字

    阅读完需:约 20 分钟

系统性能对于网站和应用程序的成功至关重要。Web Scheduler 是一个强大的工具,可以释放浏览器的潜力,提升用户体验,让你的项目脱颖而出。本篇分享将引领您深入探索 Web Scheduler 的神奇之处,揭示它如何优雅地管理各类任务,支持高频和高耗时操作,以及如何在不牺牲性能的前提下提高系统的流畅度。无论你是前端开发者、系统工程师还是对系统性能感兴趣的人,这篇分享都将帮助你解锁系统性能的新境界。

为什么需要在浏览器中进行任务调度

在浏览器中进行任务调度,就好像是一场紧张刺激的表演,其中浏览器是主角,网页是舞台,任务是精彩的节目。为什么我们需要任务调度?这就像是为了让整场表演更加精彩、顺畅,确保主角(浏览器)在不同情况下都能表现出色。


想象一下,你在观看一场精彩的舞台剧。浏览器扮演了主角,用户的交互操作是导演的指示。任务调度就像导演的计划,确保演员(浏览器)在适当的时候执行正确的动作,以便整场表演顺利进行。


任务调度有几个关键的原因:


  1. 响应用户互动:用户可能会随时点击按钮、滚动页面或执行其他操作。任务调度确保浏览器可以迅速响应这些操作,使用户体验更加流畅。

  2. 优化性能:浏览器执行任务时需要花费时间,而任务调度可以根据任务的优先级安排执行顺序。这有助于确保高优先级任务首先得到处理,提高了系统的性能和响应速度。

  3. 避免卡顿:如果所有任务都在一帧内执行,可能会导致页面卡顿或冻结。任务调度允许浏览器将任务拆分成小块,在多帧内逐步执行,避免了卡顿。

  4. 优化动画:对于需要流畅动画效果的任务,如页面滚动、元素动画等,任务调度可以将它们与页面的渲染同步,确保动画的流畅性。

每一帧,浏览器到底做了什么?

当我们打开一个网页时,我们可能并不意识到浏览器内部发生的复杂过程。但是,为了呈现出无缝的用户体验,浏览器必须在每一帧内完成一系列任务。


一帧是什么呢?你可以把一帧看作是屏幕上的一幅画面,它由许多细小的像素点组成。在每一帧内,浏览器需要完成以下六个步骤的任务:


  1. 响应用户交互事件:这是浏览器对用户操作的第一反应,如点击按钮、滚动页面等。它包括捕获和处理用户输入,以及触发相应的事件处理程序。

  2. 执行 JavaScript 代码:在这一步,浏览器会运行与页面交互和数据处理相关的 JavaScript 代码。这包括执行事件处理程序、操作 DOM 元素以及执行其他 JavaScript 功能。

  3. 帧开始:在帧开始时,浏览器会检查窗口尺寸是否发生变化,页面是否需要滚动等。这有助于浏览器准备好下一帧的渲染。

  4. rAF(requestAnimationFrame) :这是一个用于动画的浏览器 API,允许你在下一帧之前安排任务。通常用于执行需要与页面渲染同步的动画操作,以提供流畅的动画效果。

  5. 布局:在布局阶段,浏览器会计算元素的位置和大小,以确定它们在屏幕上的最终布局。这包括确定元素的位置、大小、间距等。

  6. 渲染:在渲染阶段,浏览器会将页面元素绘制成像素,呈现在屏幕上。这是将页面内容可视化的过程,包括绘制文本、图像和其他元素。


什么是时间分片

时间分片就像是为了让浏览器表演的主角(任务)不至于累坏了,给他们规定了一些休息时间。这个休息时间被划分成一小段一小段的,就像是一帧一帧的电影,每一帧都只展示一部分内容。


当浏览器执行任务的时候,有些任务可能会非常耗时,如果不分片,它们会占用很多时间,让其他任务无法执行,就像是一个舞台上的一场大戏持续演出,其他小节目都无法上台。


所以,时间分片就像是为了让每个任务都有机会上台表演,不会被长时间的大戏占据舞台。这就好比一个巡回马戏团,每个节目都有自己的时间段,观众可以欣赏到各种各样的精彩表演,而不是长时间的单一表演。


时间分片让浏览器变得更加高效和流畅,确保了用户可以享受到各种任务的精彩表演,而不会因为某个任务的耗时而卡顿或等待。这就是时间分片的妙处,它为浏览器的任务调度带来了新的活力和效率。

requestAnimationFrame、requestIdleCallback

当涉及到任务调度和时间分片时,两个关键的 API 是 requestAnimationFrame(rAF)和 requestIdleCallback


  1. requestAnimationFrame (rAF) :

  2. 目的:

  3. rAF 用于安排浏览器下一次重绘前的任务。它的目标是创建流畅的动画效果,因为它会在屏幕的每一帧之间调用回调函数,确保动画的平滑运行。

  4. 使用场景:

  5. 动画:rAF 最常用于创建 web 动画。通过在 rAF 回调中更新元素属性,您可以实现流畅的动画效果。

  6. 布局计算:因为 rAF 在每一帧之间运行,因此它非常适合于执行一些需要在渲染之前完成的任务,例如计算元素的布局信息。

  7. requestIdleCallback:

  8. 目的:

  9. requestIdleCallback 用于在浏览器的空闲时间执行任务,而不会影响用户的交互或页面的渲染。它的目标是在不阻塞主线程的情况下执行较长时间的任务。

  10. 使用场景:

  11. 延迟任务:如果您有一些任务不是立刻必需的,可以使用 requestIdleCallback 来推迟执行它们,以避免阻塞用户界面的响应性。

  12. 后台任务:这个 API 对于执行后台任务(如数据同步、分析或预取数据)非常有用,因为它能够利用浏览器的空闲时间。

  13. 任务拆分:您可以使用 requestIdleCallback 来分割较大的任务为多个小任务,以便在多个空闲周期内完成。


注意事项:


  • rAF 回调应该尽量简洁,以便在每帧内完成。如果在 rAF 回调中执行大量计算或复杂的 DOM 操作,可能会导致卡顿。

  • requestIdleCallback 回调应该被设计成可中断的,因为它可能在用户交互时被中断。这个 API 不适合执行紧急任务,而是用于后台或低优先级任务。


总结:rAF 用于动画和实时渲染,而 requestIdleCallback 用于执行非紧急任务以提高性能和用户体验。两者都有助于在浏览器中实现任务调度和时间分片,以避免卡顿和提高响应性。

为什么选择 Web Scheduler ?

当谈到使用 Web Scheduler 任务调度和时间分片来管理异步任务时,就像是为你的系统注入了一剂活力和智慧的良药。这个工具不仅能够提高系统性能,还能够让你的用户界面变得更加迅捷、顺滑,从而创造一个更美好的用户体验。


这就好比你的系统有了一个聪明的管家,它会智能地管理各种异步任务,确保关键任务第一时间完成,而非关键任务在适当的时机得到处理。你可以把这个工具看作系统中的任务调度大师,它会根据任务的优先级、时效性,以及系统资源的可用情况,智能地安排任务的执行顺序。


而时间分片技术就像系统中的魔术师,它可以将任务巧妙地分割成小块,确保没有任务会长时间占用系统资源,导致界面卡顿或失去响应。这意味着用户在与你的应用互动时,会感到更加顺畅,不再会遇到闪烁、卡顿或不响应的情况。


此外,Web Scheduler 还可以避免任务之间的相互干扰,确保每个任务都能安全地完成。它就像一个巧妙的交通管制员,管理着异步任务的流量,避免拥堵和事故。


综上所述,Web Scheduler 是一位出色的系统管理者,它为你的系统注入了活力、智慧和高效能。它将帮助你提高性能,改善用户体验,确保系统资源得到充分利用,而不被浪费。无论你是开发者还是系统管理员,它都将成为你的得力助手,让你的系统更加出色。

安装

npm install web-scheduler
复制代码

源码

npm: https://www.npmjs.com/package/web-scheduler


git: https://github.com/sullay/web-scheduler

使用

支持多种任务调度模式,对应浏览器运行的各个阶段,支持自定义任务调度。

TaskList

基于哈希表和双向跳表的任务列表,


TaskList 是一个 JavaScript 类,用于管理任务列表,用于定制化任务调度场景。它基于哈希表和双向跳表实现,允许你添加、删除和更新任务,并根据优先级和超时时间对任务进行排序。后续所有任务调度器都基于此任务列表开发。


定制化任务调度场景才会用到,正常使用只需了解运行逻辑即可。

TaskList 注意事项

  • 默认使用 symbol 当作 key 值,不需要更新任务的场景不需要设置 options.key 参数

  • 任务队列基于超时时间进行排序,优先级只影响任务的超时时间的设置

  • 默认支持的任务调度器中,会优先执行距离超时最近的任务,已超时任务会无视刷新率快速处理掉,自定义任务调度需要自行编写处理策略

  • 使用 key 值更新任务后,val 会被替换掉所以并不保证一定会执行

  • 使用 key 值更新任务后,会合并新旧的 callback 回调,所以必须要确保执行的代码请使用 callbak

  • 使用 key 值更新任务后,如果新的超时时间更紧急会向前移动任务,反之则继续使用旧任务的超时时间

  • 修改优先级对应的超时时间不影响先前插入的任务

AnimationFrameScheduler

AnimationFrameScheduler 是一个基于 requestAnimationFrame 的任务调度器,适用于动画、布局计算。


  • 执行阶段:rAF

  • 时间分片时长:默认通过估算屏幕刷新率计算。例如 fps 为 60hz,Math.floor(1000/{fps}/2) = 4ms

  • 已超时任务无视时间分片时长强制运行

AnimationFrameScheduler 示例

import { animationFrameScheduler } from 'animation-frame-scheduler';
// 设置优先级、时间分片时长await animationFrameSchedular.setConfig ({ priorityTimeoutParams: { [PRIORITY_TYPE.HIGH]: 2500, [PRIORITY_TYPE.NORMAL]: 10000, [PRIORITY_TYPE.LOW]: 50000, }, frameDuration: 5}
// 添加任务到调度器animationFrameScheduler.pushTask(() => { // 这里是任务的具体逻辑});
animationFrameScheduler.pushTask(() => conosle.log("任务2"), { key: '任务2', priority: PRIORITY_TYPE.NORMAL, callback:() => console.log("任务2 回调函数") });
复制代码

SingleAnimationFrameScheduler

SingleAnimationFrameScheduler 是一个基于 requestAnimationFrame 的任务调度器,它每帧只执行一个任务,通常用于逐帧操作动画或其他需要按帧处理的任务。这个调度器可以确保在每一帧中只执行一个任务,方便自定义动画的开发,并且避免卡顿和提供流畅的用户体验。


  • 执行阶段:rAF

  • 每一帧只执行一次,没有时间分片时长概念

  • 即使任务已经超时,也会按照排序逐帧执行

SingleAnimationFrameScheduler 示例

import {    singleAnimationFrameScheduler,} from 'web-scheduler'
const circle = document.querySelector('.circle') as HTMLElement;

circle.onclick = ()=>{ for(let i=0; i< 1000; i++){ singleAnimationFrameScheduler.pushTask(()=>{ circle.style.width = `${i}px` circle.style.height = `${i}px` }) }}
复制代码

ImmediateScheduler

ImmediateScheduler 是一个基于 setImmediate 的任务调度器,适合用于操作 DOM 元素以及执行其他 JavaScript 功能。


  • 执行阶段:JS

  • 时间分片时长:默认通过估算屏幕刷新率计算。例如 fps 为 60hz,Math.floor(1000/{fps}/2) = 4ms

  • 已超时任务无视时间分片时长强制运行

ImmediateScheduler 示例

import { immediateScheduler } from 'web-scheduler';
function fetchData() { // 模拟异步数据请求}
function processData() { // 处理数据 console.log('Data processed.');}
// 启动任务immediateScheduler.pushTask(fetchData);immediateScheduler.pushTask(processData);
复制代码

IdleFrameScheduler

IdleFrameScheduler 是一个基于 requestIdleCallback 的任务调度器,它允许你在浏览器的每一帧的空闲时间执行任务。这样可以最大程度地利用计算资源,特别适用于执行非关键任务。


  • 执行阶段:Paint 之后执行

  • 时间分片时长:浏览器渲染一帧全部工作完成后的剩余时长 (1000/{fps} - 已用时长)

  • 已超时任务无视时间分片时长强制运行

  • 主要用于执行非关键任务,以充分利用浏览器的空闲时间。不建议将关键任务放在此调度器中,如果一直没有空闲时间,任务会超时后才能执行。

IdleFrameScheduler 示例

import { idleFrameScheduler } from 'web-scheduler';
function log() { // 打印日志}function report() { // 上报数据}
// 启动任务idleFrameScheduler.pushTask(log);idleFrameScheduler.pushTask(report);
复制代码

使用场景举例

  1. 动画优化:使用AnimationFrameScheduler可以实现流畅的动画效果。这适用于各种动画,如页面元素的平滑移动、渐变变化和元素的逐帧操作。任务调度确保动画操作与页面渲染同步,提供更好的用户体验。

  2. 网络请求管理:在应用程序中,可能需要同时处理多个网络请求。通过使用任务调度,您可以设置不同网络请求的优先级,确保关键数据请求优先进行,而非关键请求等待空闲时间执行。这有助于最大程度地利用网络资源。

  3. 数据同步:对于需要与服务器同步数据的应用程序,您可以使用IdleFrameScheduler来执行数据同步任务。这样,数据同步可以在浏览器的空闲时间内进行,而不会干扰用户的操作和页面渲染。

  4. 图片加载:当加载大量图片时,使用任务调度可以确保页面的渲染不会被阻塞。您可以将图片加载任务设置为低优先级,以便在用户操作时不会受到干扰。

性能优化技巧

  1. 任务拆分:将长时间运行的任务拆分为多个小任务,以便在多个空闲周期内完成。这可以通过合理设置任务的优先级和超时时间来实现。任务拆分可以防止长时间任务阻塞页面渲染和用户交互。

  2. 智能超时时间设置:合理设置不同任务的优先级和超时时间非常关键。高优先级任务应该具有较短的超时时间,以确保它们尽快执行,而低优先级任务可以具有较长的超时时间,以等待浏览器的空闲时间。

  3. 实时性需求:根据任务的实时性需求选择合适的任务调度器。如果任务需要立即执行,可以使用ImmediateScheduler;如果任务可以稍后执行,可以使用IdleFrameScheduler。这有助于更好地管理任务的执行顺序。

  4. 避免过度使用:尽管任务调度和时间分片非常有用,但不要过度使用它们。在某些情况下,简单的异步操作可能更有效。选择适当的工具和技术来处理任务,以避免复杂性。

  5. 性能监控:使用性能分析工具和浏览器开发者工具来监控任务调度的性能。这可以帮助您识别性能瓶颈和改进任务的执行效率。


通过更深入了解任务调度和时间分片的使用场景以及性能优化技巧,您可以更好地应用这些概念,提高系统性能,改善用户体验,避免页面卡顿和提高响应速度。任务调度和时间分片是强大的工具,可以帮助您在浏览器中管理异步任务,使您的应用程序更加出色。

Art JS

art-js 是一个类似于 react 的虚拟 dom 框架,使用 Web Scheduler 在没有过多编译时优化的情况下,实现了出色的性能表现。https://krausest.github.io/js-framework-benchmark/


以下是js-framework-benchmark跑分中与主流框架的一些性能对比。





总结

Web Scheduler 是一个强大的工具,用于管理浏览器中的异步任务,提高性能、优化用户体验。它采用任务调度和时间分片技术,确保任务按优先级、时效性和系统资源的可用性得以执行。这些调度器可根据任务的需求和应用场景选择不同的执行逻辑,提供了灵活性和定制化的可能性。无论你是前端开发者、系统工程师还是对系统性能感兴趣的人,Web Scheduler 都值得你深入学习和尝试,以提升你的技能和项目的表现。


通过 Web Scheduler,你可以更好地管理任务,确保用户界面的流畅性,避免卡顿和失去响应。它为你的系统注入了智能和高效性,提高了系统的性能和用户体验。无论你的项目规模如何,Web Scheduler 都能成为你的得力助手,让你的项目更加出色。祝你在任务调度的旅程中取得成功!


【参考文章】


【1】https://developer.chrome.com/blog/using-requestidlecallback/


【2】https://developer.mozilla.org/en-US/docs/Web/API/IdleDeadline


【3】https://web.dev/articles/rail?hl=zh-cn


【4】https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame


【5】https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback


【6】https://github.com/sullay/web-scheduler


【7】https://www.npmjs.com/package/web-scheduler

发布于: 刚刚阅读数: 6
用户头像

。。。

关注

还未添加个人签名 2019-08-09 加入

还未添加个人简介

评论

发布
暂无评论
释放浏览器潜力:Web Scheduler 背后的系统性能提升_前端_。。。_InfoQ写作社区