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

系统性能对于网站和应用程序的成功至关重要。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) :

    • 目的:

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

      • 动画:rAF 最常用于创建 web 动画。通过在 rAF 回调中更新元素属性,您可以实现流畅的动画效果。
      • 布局计算:因为 rAF 在每一帧之间运行,因此它非常适合于执行一些需要在渲染之前完成的任务,例如计算元素的布局信息。
  2. requestIdleCallback:

    • 目的:

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

      • 延迟任务:如果您有一些任务不是立刻必需的,可以使用 requestIdleCallback 来推迟执行它们,以避免阻塞用户界面的响应性。
      • 后台任务:这个 API 对于执行后台任务(如数据同步、分析或预取数据)非常有用,因为它能够利用浏览器的空闲时间。
      • 任务拆分:您可以使用 requestIdleCallback 来分割较大的任务为多个小任务,以便在多个空闲周期内完成。

注意事项:

  • rAF 回调应该尽量简洁,以便在每帧内完成。如果在 rAF 回调中执行大量计算或复杂的 DOM 操作,可能会导致卡顿。
  • requestIdleCallback 回调应该被设计成可中断的,因为它可能在用户交互时被中断。这个 API 不适合执行紧急任务,而是用于后台或低优先级任务。

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

为什么选择 Web Scheduler ?

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

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

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

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

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

安装

bash 复制代码
npm install web-scheduler

源码

npm: www.npmjs.com/package/web...

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

使用

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

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示例

ts 复制代码
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示例

ts 复制代码
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示例

ts 复制代码
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示例

ts 复制代码
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在没有过多编译时优化的情况下,实现了出色的性能表现。 krausest.github.io/js-framewor...

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

总结

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

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

【参考文章】

【1】developer.chrome.com/blog/using-...

【2】developer.mozilla.org/en-US/docs/...

【3】web.dev/articles/ra...

【4】developer.mozilla.org/en-US/docs/...

【5】developer.mozilla.org/en-US/docs/...

【6】github.com/sullay/web-...

【7】www.npmjs.com/package/web...

相关推荐
IT女孩儿1 小时前
CSS查缺补漏(补充上一条)
前端·css
吃杠碰小鸡2 小时前
commitlint校验git提交信息
前端
虾球xz2 小时前
游戏引擎学习第20天
前端·学习·游戏引擎
我爱李星璇2 小时前
HTML常用表格与标签
前端·html
疯狂的沙粒3 小时前
如何在Vue项目中应用TypeScript?应该注意那些点?
前端·vue.js·typescript
小镇程序员3 小时前
vue2 src_Todolist全局总线事件版本
前端·javascript·vue.js
野槐3 小时前
前端图像处理(一)
前端
程序猿阿伟3 小时前
《智能指针频繁创建销毁:程序性能的“隐形杀手”》
java·开发语言·前端
疯狂的沙粒3 小时前
对 TypeScript 中函数如何更好的理解及使用?与 JavaScript 函数有哪些区别?
前端·javascript·typescript
瑞雨溪3 小时前
AJAX的基本使用
前端·javascript·ajax