实现workloop

大家好,我是万维读客的讲师曹欢欢。上节学习了fiber异步渲染原理和数据模型,这里我们开始构建异步渲染模型workloop,逐步构建fiber节点树。

测试用例

创建一个treact03文件夹,创建测试用例jsx.test.jsx,测试treact异步渲染能力,测试用例代码如下:

import {describe, it, expect} from 'vitest';
import * as Treact from './Treact';

function wait(){
    return new Promise((resolve, reject)=>{
        setTimeout(()=>{
            resolve(1);
        }, 500);
    });
}

describe('async render',()=>{
    it('render in async', async ()=>{
        const ele = (
        <div className="container">
            <span>hello</span>
            <a>w3cdoc.com</a>
        </div>);
        const container = document.createElement('div');
        const root = Treact.createRoot(container);
        root.render(ele);
        expect(container.innerHTML).toBe('');
        await wait();
        expect(container.innerHTML).toBe('<div class="container"><span>hello</span><a>w3cdoc.com</a></div>');
    })
})

render函数执行后,同步root.container.innerHTML的内容没有更新,所以应该是空的。我们异步等待一段时间,然后root.container.innerHTML应该能更新到最终渲染结果。

查看控制台肯定会报错,这时候我们来把render函数修改成异步。

实现异步render

我们参考上一节学习的fiber的原理和react相关的代码,修改treat代码结构如下:

let workInProgress = null;     // 当前fiber节点
let workInProgressRoot = null; // 所有fiber节点的root节点

class TreactRoot {
    _internalRoot = null;
    constructor(container) {
        // this.container = container;
        this._internalRoot = {
            current: null,
            containerInfo: container
        }
    }
    workloop(){
        while(workInProgress){
            workInProgress = this.performUnitOfWork(workInProgress);
        }
    }
    performUnitOfWork(fiber){
        // 具体执行fiber节点渲染的逻辑
    }
    render(element) {
        // this.renderElement(element, this.container);
        this._internalRoot.current = {
            alternate: {
                stateNode: this._internalRoot.containerInfo,
                props:{
                  children: [element]
                }
            }
        }
        workInProgressRoot = this._internalRoot;
        workInProgress = this._internalRoot.current.alternate;
        setTimeout(this.workloop.bind(this));
    }

上面的代码我们先初始化了workInProgress和workInProgressRoot 这两个节点,其中workInProgressRoot是所有fiber节点的根节点,然后我们来构建fiber节点树。

我们修改了构造函数方法,通过_internalRoot来存储当前根节点容器,然后在render方法中来初始化alternate这个fiber节点,并设置根节点fiber和当前要处理的fiber节点。

最后开始异步调用workloop函数,这里先简单用定时器实现,后面会用调度器来替代。workloop函数中也是通过循环来执行fiber节点的渲染逻辑,暂时没有实现yield让出控制权,后面通过调度器一起实现。

这里我们整体构建好了workloop异步渲染的框架,下一步就可以开始实现fiber节点渲染了。

参考

  1. performConcurrentWorkOnRoot 源码:https://github.com/facebook/react/blob/4f29ba1cc52061e439cede3813e100557b23a15c/packages/react-reconciler/src/ReactFiberWorkLoop.old.js#L824
  2. workLoopConcurrent源码:https://github.com/facebook/react/blob/4f29ba1cc52061e439cede3813e100557b23a15c/packages/react-reconciler/src/ReactFiberWorkLoop.old.js#L1824-L1829
  3. Fiber节点:https://github.com/facebook/react/blob/4f29ba1cc52061e439cede3813e100557b23a15c/packages/react-reconciler/src/ReactInternalTypes.js


请遵守《互联网环境法规》文明发言,欢迎讨论问题
扫码反馈

扫一扫,反馈当前页面

咨询反馈
扫码关注
返回顶部