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

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 () 执行宏任务;

优先级;

这里不做详细说明。

相关推荐

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

    2024-02-17 06:00:06       49 阅读
  2. reactdiff算法

    2024-02-17 06:00:06       55 阅读
  3. React的Keydiff

    2024-02-17 06:00:06       35 阅读
  4. vuereact diff的详解不同

    2024-02-17 06:00:06       71 阅读
  5. vuereactdiff算法源码

    2024-02-17 06:00:06       47 阅读
  6. react diff 原理

    2024-02-17 06:00:06       46 阅读
  7. ReactDiff算法

    2024-02-17 06:00:06       37 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-02-17 06:00:06       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-02-17 06:00:06       106 阅读
  3. 在Django里面运行非项目文件

    2024-02-17 06:00:06       87 阅读
  4. Python语言-面向对象

    2024-02-17 06:00:06       96 阅读

热门阅读

  1. Vue3 中应该使用 Ref 还是 Reactive?

    2024-02-17 06:00:06       61 阅读
  2. 【VTKExamples::PolyData】第二十八期 LinearExtrusion

    2024-02-17 06:00:06       44 阅读
  3. docker的常用命令有哪些?

    2024-02-17 06:00:06       45 阅读
  4. Lua:面向对象/C之间的交互

    2024-02-17 06:00:06       51 阅读
  5. Docker安装和使用MySQL

    2024-02-17 06:00:06       47 阅读
  6. 假期2.13

    2024-02-17 06:00:06       49 阅读
  7. 软件系统架构演变:从单体应用到微服务

    2024-02-17 06:00:06       53 阅读