美文网首页
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