美文网首页
fiber架构(执行顺序)

fiber架构(执行顺序)

作者: Mr无愧于心 | 来源:发表于2021-05-19 15:53 被阅读0次

    链表对比递归

    因为fiber架构要用每一帧的空闲时间执行任务,那么任务列表是会被中断的,
    如果使用递归的话,查找当前需要执行的任务时,每次都要从根节点开始遍历,效率反而会降低。
    使用链表的话,有个 Fiber 其单链表(Linked List)结构为 A → B → C,当 A 执行到 B 被中断的话,可以之后再次执行 B → C,时间复杂度是O(1)。

    fiber链表单元结构

    Fiber 可以理解为是一种数据结构,React Fiber 就是采用链表实现的。每个 Virtual DOM 都可以表示为一个 fiber,

    // 部分结构,其实就是一个对象数据结构
    {
        alternate: Fiber|null, // 在fiber更新时克隆出的镜像fiber,对fiber的修改会标记在这个fiber上(实际上是两颗fiber数,用于更新缓存,提升运行效率)
        nextEffect: Fiber | null, // 单链表结构,方便遍历 Fiber Tree 上有副作用的节点
        pendingWorkPriority: PriorityLevel, // 标记子树上待更新任务的优先级 
        stateNode: any, // 管理 instance 自身的特性
        return: Fiber|null, // 指向 Fiber Tree 中的父节点
        child: Fiber|null, // 指向第一个子节点
        sibling: Fiber|null, // 指向兄弟节点
    }
    fiber单元之间的关联关系组成fiber tree,fiber tree是根据 VDOM tree 构造出来的,树形结构完全一致,只是包含的信息不同
    
    

    fiber树

    根据以下的dom结构会生成一个相应的fiber树(如图)

    let root = {
        key: 'A1',
        children: [
            {
                key: 'B1',
                children: [
                    { key: 'C1', children: [] },
                    { key: 'C2', children: [] },
                ]
            },
            {
                key: "B2", children: []
            }
        ]
    }
    
    image.png

    fiber的执行顺序的原则是

    儿子 ===》兄弟 ===》叔叔
    image.png

    fiber render阶段链表执行顺序实现

    根据以上dom树生成的简易fiber树(实现方式在下一节说明)

    let A1 = { type: 'div', key: 'A1'};
    let B1 = { type: 'div', key: 'B1', return: A1 }
    let B2 = { type: 'div', key: 'B2', return: A1 }
    let C1 = { type: 'div', key: 'C1', return: B1 }
    let C2 = { type: 'div', key: 'C2', return: B1 }
    A1.child = B1;
    B1.sibling = B2;
    B1.child = C1;
    C1.sibling = C2;
    

    fiber单元执行顺序

    let nextUnitOfWork = null;//下一个执行单元
    let startTime = Date.now();
    function workLoop(deadline) {
        //while (nextUnitOfWork) {//如果有待执行的执行单元,就执行,然后会返回下一个执行单元
        while ((deadline.timeRemaining() > 1 || deadline.didTimeout) && nextUnitOfWork) {
            nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
        }
        if (!nextUnitOfWork) {
            console.log('render阶段结束了');
            
        } else {//请求下次浏览器空闲的时候帮我调
            requestIdleCallback(workLoop, { timeout: 1000 });
        }
    }
    
    function performUnitOfWork(fiber) {
        beginWork(fiber);//处理此fiber
        if (fiber.child) {//如果有儿子,返回大儿子
            return fiber.child;
        }//如果没有儿子,说明此fiber已经完成了
        while (fiber) {
            completeUnitOfWork(fiber);
            if (fiber.sibling) {
                return fiber.sibling;//如果说有弟弟返回弟弟
            }
            fiber = fiber.return;// 如果没有弟弟当前的fiber指向自己的父亲,父亲也完成了,继续循环返回父亲的弟弟
        }
    }
    
    function completeUnitOfWork(fiber) {
        console.log('结束', fiber.key);// C1 C2 B1 B2 A1
    }
    
    function beginWork(fiber) {
        sleep(20);
        console.log('开始', fiber.key);//A1 B1 C1 C2  B2
    }
    
    nextUnitOfWork = A1;
    
    requestIdleCallback(workLoop, { timeout: 1000 });
    
    image.png

    相关文章

      网友评论

          本文标题:fiber架构(执行顺序)

          本文链接:https://www.haomeiwen.com/subject/xzypjltx.html