Fiber是对react核心算法的重构,react16以上版本引入了fiber架构,此中的计划头脑很值得我们去学习。
那fiber是什么呢?
- fiber是一个实行单位
- fiber也是一种数据布局
在没引入fiber之前,React会递归比对VirtualDOM树,找出必要变更的节点,然后同步更新它们。这个过程React称为Reconciliation(调和)。在Reconciliation过程中,React会不停占用着欣赏器资源,如果更新节点庞大,那么用户触发的事故大概得不到回馈大概出现卡顿。
fiber的出现则是把庞大的更新节点分割为一个个小的任务单位,欣赏器可以在react和相应时间中切换控制权,从而到达优化效果。
fiber的可停止、继承是基于 欣赏器的 requestIdleCallback api实现的。现在大多欣赏装备每秒革新60次,requestIdleCallback 函数每一帧会返回这一秒渲染完成后剩余的时间,React就会查抄现在还剩多少时间,如果没偶然间就将控制权交还欣赏器;然后继承举行下一帧的渲染。
假造dom转化成fiber后,会有这几个属性,去指向下一个实行单位。
- child(child指的是第一个子节点而不是全部的子节点)
- sibling 指的是下一个兄弟节点(弟弟)
- return 指向父节点
<div id="A1"> <div id="B1"> <div id="C1"></div> <div id="C2"></div> </div> <div id="B2"></div><div>如许的jsx如果要转成fiber则会是这个样子
详情可以戳 -> 在react中,假造dom是怎样转化为fiber链表的?
// element.jslet A1 = { key: 'A1', type: 'div' }let B1 = { key: 'B1', type: 'div', return: A1 }let B2 = { key: 'B2', type: 'div', return: A1 }let C1 = { key: 'C1', type: 'div', return: B1 }let C2 = { key: 'C2', type: 'div', return: B1 }A1.child = B1B1.sibling = B2B1.child = C1C1.sibling = C2module.exports = A1fiber的遍历顺序是由根节点开始的,优先级 child > sibling > return
所以遍历的先后顺序是
- A1.child (B1)
- B1.child (C1)
- C1.sibling (C2) C1没有child了,就去找它的兄弟
- C2.return (B1) C2 既没有child,又没有sibling,就去找它的 父节点 return
- B1.sibling (B2) B1的child已经被遍历过了,就去找它的sibling
- B2.return (A1)
开始遍历
let rootFiber = require('./element')let nextUnitOfWork = nullfunction workLoop() { while(nextUnitOfWork) { nextUnitOfWork = performUnitOfWork(nextUnitOfWork) }}function performUnitOfWork(currentFiber) { // 返回下一个实行单位 beginWork(currentFiber) if (currentFiber.child) { return currentFiber.child } // 如果能走到这一步,证实遍历到 C1 了 while(currentFiber) { // 由于此处大概 sibling不肯定只有一个,所以要进入while循环 if(currentFiber.sibling) { return currentFiber.sibling } // 如果没有sibling了,就会到其父节点 return currentFiber.return }}function beginWork(currentFiber) { // 本章重要纪录fiber是怎么遍历的,所以就不去做别的事情啦 console.log(currentFiber.key)}nextUnitOfWork = rootFiberworkLoop()写到这块是不是少了些什么东西呢?哦对,没有写怎么去让它变成可停止、可规复的遍历,那就必要祭出上面提出的requestIdleCallback了
我们只必要对workLoop作出小小改动即可
function workLoop(deadline) { // timeRemaining() 是指当前渲染完留给react调理的时间 while ((deadline.timeRemaining() > 1 && nextUnitOfWork) { nextUnitOfWork = performUnitOfWork(nextUnitOfWork); } if (!nextUnitOfWork) { console.log('render阶段遍历竣事') } else { requestIdleCallback(workLoop, { timeout: 500 }); }}requestIdleCallback(workLoop, { timeout: 500 });timeout是指的超时时间,意思是,如果超过500ms还没做我的事的话,那你必须放动手头工作,立刻去继承实行workLoop。
如许我们关于fiber链表是怎么遍历的就完成啦!
资料参考: 从零实现React16 Fiber架构与Hooks源码
|