解决目标对象更快完成渲染
与及时响应优先级更高任务
之间的矛盾。
Perceived performance 可感知到的性能
在流畅性的章节中提到将主线程的一个长任务进行时间分片
可以拆分为多个帧任务, 但如果同时存在多个任务则必然会存在一种竞争机制, 于是需要一种 Schedule
机制, 在时间分片中加入动态优先级
的概念来真正避免卡顿现象。
调度算法思想:
在一帧中执行的任务种类有以下几种类别:
user-blocking tasks
: 基于用户的交互的任务(可见), 需在当前帧处理; -> input
、rAF
、microtask
(顺畅的交互应小于 10 ms, 下同)default tasks
: 基于用户获取数据渲染到界面上的任务(可见), 在当前的帧以及下一帧里处理; -> macrotask
(小于 100 ms)idle tasks
: 和分析、缓存、排序相关的任务(不可见); -> requestIdleCallback
(小于 10 ms)不能拆分的任务(执行时间较长的 chunk)怎么办?
借助 web Worker
任务的排序机制是由 expiration time
这个字段决定的,其值为 callback 的注册时间
与当前任务优先级的值
之和, 表示过期时间(值越小, 越早执行)。
优先级的值分为以下几种类别:
Immediate
: (0ms timeout)需要实时交互的任务; (Do it now)User Block
: (250ms timeout)对页面交互有副作用的任务; (Do it now)Normal
: (5s timeout)不影响交互的任务; (Do it soon)Low
: (10s timeout)可以延迟执行,但最终需要执行的任务; (Do it eventually)Idle
: (no timeout)执行与否不影响应用的任务; (Do it if you can)在了解了 expiration time
之后, 对 Schedule
的流程进行如下概述:
expiration time
排好序放入一个队列中;Schedule
自己注册一个回调 callback 调用该队列,并下一个帧中执行它;Schedule 中 4 个比较重要的方法的作用罗列如下:
JND(Just Noticeable Difference), JND
// Computes the next Just Noticeable Difference (JND) boundary.// The theory is that a person can't tell the difference between small differences in time.// Therefore, if we wait a bit longer than necessary that won't translate to a noticeable// difference in the experience. However, waiting for longer might mean that we can avoid// showing an intermediate loading state. The longer we have already waited, the harder it// is to tell small differences in time. Therefore, the longer we've already waited,// the longer we can wait additionally. At some point we have to give up though.// We pick a train model where the next boundary commits at a consistent schedule.// These particular numbers are vague estimates. We expect to adjust them based on research.function jnd(timeElapsed: number) {return timeElapsed < 120? 120: timeElapsed < 480? 480: timeElapsed < 1080? 1080: timeElapsed < 1920? 1920: timeElapsed < 3000? 3000: timeElapsed < 4320? 4320: ceil(timeElapsed / 1960) * 1960;}
Time Slicing
is the premise of Suspense
. Because in each time slicing it can compare the task priority, and then determine whether to show the loading.
requestIdleCallback
, 其有更简洁的 api;