vue3 源码解读之 time slicing的使用方法

2020-06-12 21:05:39易采站长站整理

}
else {
break;
}
{
const now = getNow();
if (now - flushStartTimestamp > frameBudget && job.expiration > now) {
break; // 此处为关键,意思是超过16ms,或者任务过期,跳出循环
}
}
}
... 以下代码省略...

上面的循环很关键,它做的事情很简单的,从 stageQueue 里出栈一个任务,然后执行 stateJob

stateJob 做的事情很简单,就是往 commitQueue 里 push 这个任务


function stageJob(job) {
if (job.ops.length === 0) {
currentJob = job;
job.cleanup = job();
currentJob = null;
commitQueue.push(job); //重点在这里
job.status = 2;
}
}

到目前为止,我们源码读了一丢丢,但是已经几乎读完了可以说

它的本质就是,在宏任务中,stageQueue 作为低优先级任务队列,不断的出栈,然后分批次(16ms 的阈值)入栈到 commitQueue 里

呼,其实如果不是写文章,就可以到此为止了,但是写文章为了凑字数嘛,我们继续

上面我们已经知道了两个队列,stageQueue 和 commitQueue,但是并不知道他们里面都是什么东西

是什么东西被调度的呢?打印一下,你就知道:


console.log(stageQueue,commitQueue)

得出的结果是


function mountComponentInstance(){...}

看名字就知道是组件挂载函数,当然组件更新和卸载的函数也是同理

到现在,我们也知道了参与调度的是组件挂载更新的函数,所以本质上,vue 的时间切片的基本单位是组件,也就是说,如果你的组件挂载需要一个小时,那你仍然要卡一小时

凑字数

剩下的内容纯属凑字数,就是除了核心调度之外的东西

比如 commitQueue 是操作 dom 的,那它咋个操作


function commitJob(job) {
const { ops, postEffects } = job;
for (let i = 0; i < ops.length; i++) {
applyOp(ops[i]); // 重点在这里
}
if (postEffects) {
postEffectsQueue.push(...postEffects);
}
resetJob(job);
job.status = 0;
}

如上,拿到 ops,然后进行操作,我们看一下 ops 是啥就行了


[<div></div>, <li></li>, function CreactElement(){}]

凑合凑合,是个数组,包含了 dom 操作的方法和被操作的元素

然后这个过程是同步完成的,也就是所谓的高优先级任务,必须等到彻底收集完毕,才可以循环执行它

做完这个,postEffectQueue 主要是一些额外的副作用和清理工作,我实在凑字数无能,就不打印了