react中如何做到中断diff过程和恢复

231 篇文章 1 订阅
30 篇文章 0 订阅

workLoop是 实现时间切片 和 可中断渲染的核心,简要说明如下:

// 并发任务的入口

function workLoopConcurrent() {

    // Perform work until Scheduler asks us to yield

    // 有任务 & 是否需要中断

    while (workInProgress !== null && !shouldYield()) {

        performUnitOfWork(workInProgress);

    }

}

const scheduler = {

    // 任务放到队列里,等待空闲执行

    taskQueue: [

        {

            // 每个任务是个回调的概念, 且回调任务是可中断的

            callback: workLoopConcurrent

        }

    ],


    // 判断: 是否需要中断, 将控制权交给主进程

    shouldYieldToHost() {

        // 没有剩余时间

        if (currentTime >= deadline) {

            // 但需要渲染 和 有更高优任务

            if (needsPaint || scheduling.isInputPending()) {

                return true; // 中断

            }

            // 是否超过 300ms

            return currentTime >= maxYieldInterval;

        }


        // 还有剩余时间

        return false;

    },


    // 执行入口可见

    workLoop() {

        // 当前第一个任务
        currentTask = taskQueue[0];
        // 每次 currentTask 退出 就是一个时间切切片

        while (currentTask !== null) {

            // 任务没有过期, 但一帧已经无可用时间 或 需要被中断, 则让出主线程

            // 每一次执行均进行超时检测,做到让出主线程。
            // expirationTime >currentTime: 任务已过期
            // hasTimeRemaining :有剩余时间
			// shouldYieldToHost:是否暂停任务,让出主线程
            if (currentTask.expirationTime > currentTime

                && (!hasTimeRemaining || shouldYieldToHost())) {
                break;
            }

            // 表示任务到了过期时间,并且有剩余时间来执行,没有到达需要浏览器渲染的时候
            // 那么我们执行任务

            const callback = currentTask.callback;// 拿到任务

            const continuationCallback = callback(didUserCallbackTimeout);// 执行任务

            // 如果该任务后, 还有连续回调

            if (typeof continuationCallback === 'function') {

                // 则保留当前

                currentTask.callback = continuationCallback;

            } else {

                // 将currentTask移除该队列

                pop(taskQueue);

            }
            // 更新currentTask,取出任务优先级最高的那个任务

            currentTask = peek(taskQueue);

        }

    },

}

简而言之:

有个任务队列 queue,该队列存放可中断的任务。

workLoop对队列里取第一个任务currentTask,进入循环开始执行。

如果任务执行完后,还有连续的回调,则 currentTask.callback = continuationCallback

否则移除已完成的任务

当该任务没有时间 或 需要中断 (渲染任务 或 其他高优任务插入等),则让出主线程。

否则执行任务 currentTask.callback()

更新任务currentTask,继续循环走起。

这里还涉及更多细节,例如:

requestAnimationFrame 计算一帧的空余时间;

使用new MessageChannel () 执行宏任务;

优先级;

这里不做详细说明。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值