::>_<:: halo,大家好,俺又出来蹦跶了
昨天写完代码好晕,以为要歇菜了
今天给大家分享的是 fre 新版本中的优先级调度,和 hash.keyed 算法
优先级调度
其实优先级调度,通俗理解就是,高优先级的任务一定会执行,并且尽可能快的执行,低优先级的任务,有空就执行
我之前写过一个小库,通过 promise 模拟 requestIdleCallback
大家可以跑一下 readme 的用例
react 的 调度方案
在 react 中,它通过 rAF 模拟 rIC
module.exports = {
NoWork: 0, // No work is pending.
SynchronousPriority: 1, // For controlled text inputs. Synchronous side-effects.
TaskPriority: 2, // Completes at the end of the current tick.
HighPriority: 3, // Interaction that needs to complete pretty soon to feel responsive.
LowPriority: 4, // Data fetching, or result from updating stores.
OffscreenPriority: 5, // Won't be visible but do the work in case it becomes visible.
}
复制代码
它的调度过程更加复杂,我还没太搞懂
所以 fre 的调度是直接使用了 rIC 和 rAF
我们先规定,fiber 的遍历过程,是低优先级的任务,而 commit 过程是高优先级任务
requstIdleCallback(function workLoop(deadline){
while(tasks.length && deadline.timeRemaining() > 0){
tasks.shift()()
}
if(tasks.length){
requestIdleCallback(workLoop)
}
requestAnimationFrame(()=>{
parent.insertBefore(dom,insertPoint) //dom 操作,高优先级
})
})
复制代码
以上,代码表示,差不多就是这个意思,当然 fre 源码可能稍稍复杂一些
但是套路都是一样的,整个便利过程放到 rIC 的回调里,dom 操作 放到 rAF 的回调里
平时我们在工作中也可以这么干,很多东西适合做优先级调度的,比如数据库,请求,sw回调……
为了兼容 ie,我还写了 polyfill
export const rIC =
requestIdleCallback ||
((cb, start = Date.now()) =>
setTimeout(() => {
cb({
didTimeout: false,
timeRemaining: () => Math.max(0, 50 - (Date.now() - start))
})
}, 1))
export const rAF = requestAnimationFrame || setTimeout
复制代码
hash.keyed 排位算法
关于这个算法,昨天发过一篇文章:juejin.im/post/5cd62b…
其实也没啥,就是通过 hash 去标号,方便对号操作
但是有了这个算法,diff 的效率至少比单独的 keyed 要高一点的
总结
fre 从 v1.3 往后,无论是 diff 还是调度,都基本完善,之前做了很多尝试与研究
其实最大的挑战是尺寸,很多次都超标(2kb)
最终加上 polyfill,拼了老命才把尺寸降到 1.8kb
其实过度追求尺寸没什么太大的必要,但是总感觉 1kb 就是逼格高,哈哈