你好,我是本文作者南一。如果有发现错误或者可完善的地方,恳请斧正,万分感谢!!
React中的时间分片是怎么做的?
React从scheduler包中导入两个函数:unstable_shouldYield和unstable_scheduleCallback。
unstable_scheduleCallback函数的作用是使用宏任务调度比较工作,使比较工作在浏览器完成一帧渲染之后执行,而比较工作就在render阶段完成,render过程就会使用unstable_shouldYield函数判断 5ms 时间到了没?如果到了就中断,此时 JS 线程空闲,浏览器可以利用这段间隙处理用户输入、动画和 UI 渲染;如果没到就继续比较下一个节点。
因此,只要使用宏任务调度,就可以完成在浏览器渲染之后执行的目的,不管是setImmediate、setTimeout还是MessageChannel都能胜任。
在浏览器环境中,由于MessageChannel执行时机更靠前,所以如果浏览器支持的话会优先选MessageChannel,其次才是setTimeout。
而在 Node 环境中 setImmediate 的执行时机比这俩还要靠前,因此也变成Node环境中调度任务的首选了。
知道了如何中断,那如何继续的呢?
React会保留当前正在处理的 Fiber 节点指针,并返回一个续点函数,unstable_scheduleCallback内部会将函数继续压入任务队列,然后吊起一个新的宏任务,等待下一轮事件循环的到来。
优先级又是怎么实现打断?
每次递归调用,都会取出当前优先级与前一次优先级进行比较,如果一样则继续前一次的工作;如果更高优,那么直接吊起一次新的调度,且是从根节点重新开始。
与此同时,如果优先级高到是需要同步执行的,那么会用微任务调度工作,否则就还是用宏任务。