的和谐。Fiber架构是React16中引入的一个新概念。目的是为了解决大型React应用的滞后问题。它使用的是虚拟DOM,所以可以理解为fiber就是React的虚拟DOM。更新光纤的过程称为协调。每个fiber都可以作为一个执行单元来处理,所以每个fiber都可以根据自己的过期时间来判断是否是。仍有空间和时间来执行更新。如果来不及更新,浏览器就必须主动去渲染,做一些动画,回流(reflow),重绘repaints等等,这样给用户的感觉就不太好。卡片。2什么是reconciliationReconciliation是一种算法,是React比较新旧虚拟DOM,决定哪些部分需要更新的过程。3.什么是FilberFiber?FilberFiber的目的是让React充分利用调度,以便执行以下操作:暂停工作,稍后再回来需求,我们需要将任务拆分为可执行单元。这些可执行单元称为纤程,纤程代表一个可执行单元。Fiber是一个普通的JS对象,其中包含有关某些组件的信息。函数FiberNode(){this.tag=tag;//fiber标签证明它是什么类型的光纤。this.key=键;//协调子节点时使用键。this.type=null;//dom元素是对应的元素类型,比如div,component指向该组件对应的类或函数。this.stateNode=null;//指向对应的真实dom元素,class组件指向组件实例,可以通过ref获取。this.return=null;//指向父纤维this.child=null;//指向子纤程this.sibling=null;//指向兄弟fiberthis.index=0;//索引this.ref=null;//ref指向ref函数或ref对象。this.pendingProps=pendingProps;//在更新中,代表元素创建this.memoizedProps=null;//记录上次更新后的propsthis.updateQueue=null;//类组件存储setState更新队列,函数组件存储this.memoizedState=null;//类组件保存状态信息,函数组件保存hooks信息,dom元素为nullthis.dependencies=null;//上下文或时间依赖this.mode=mode;//描述fiber树模式,比如ConcurrentMode模式this.effectTag=NoEffect;//effect标签,用于收集effectListthis.nextEffect=null;//指向下一个效果this.firstEffect=null;//第一个效果this.lastEffect=null;//最后一个效果this.expirationTime=NoWork;//使用不同的过期时间来判断任务是否过期,在v17版本中用lane表示。this.alternate=null;//双缓存树,指向缓存的纤程。在更新阶段,两棵树相互交替。}type是react的元素类型exportconstFunctionComponent=0;//对应的功能组件exportconstClassComponent=1;//对应类组件exportconstIndeterminateComponent=2;//初始化的时候不知道是函数组件还是类组件exportconstHostRoot=3;//RootFiber可以理解为reactDom.render()生成的根元素exportconstHostPortal=4;//对应ReactDOM.createPortal生成的PortalexportconstHostComponent=5;//dom元素例如,
exportconstHostText=6;//文本节点exportconstFragment=7;//对应于
exportconstMode=8;//对应于exportconstContextConsumer=9;//对应于exportconstContextProvider=10;//对应exportconstForwardRef=11;//对应React.ForwardRefexportconstProfiler=12;//对应exportconstSuspenseComponent=13;//对应于ex端口常量MemoComponent=14;//例如React.memo返回的组件,元素结构如下:exportdefaultclassParentextendsReact.Component{render(){returnhello,world
}}functionChild(){returnchild
}对应的Filber结构如下:有了上面的概念,我们自己实现一个Fiber更新机制。4.实现对帐过程,我们通过Render一段jsx来说明React的对帐过程,即需要实现ReactDOM.render()constjsx=(你好
React)ReactDOM.render(jsx,document.getElementById('root'));1.创建FiberRootreact-dom.jsfunctioncreateFiberRoot(element,container){return{type:container.nodeName.toLocaleLowerCase(),props:{children:element},stateNode:container}}functionrender(element,container){constFibreRoot=createFiberRoot(元素,容器)scheduleUpdateOnFiber(FibreRoot)}导出默认{render}2.render阶段和解的核心是render和commit。本文不谈调度过程。我们将简单地使用requestIdleCallback而不是React的调度过程。ReactFiberWorkloop.jsletwipRoot=null//workinprogressletnextUnitOfwork=null//nextfiberNode导出函数scheduleUpdateOnFiber(fiber){wipRoot=fibernextUnitOfwork=fiber}functionworkLoop(IdleDeadline){while(nextUnitOfwork&&IdleDeadline.timeRemaining()>0){nextUnitOfwork=performUnitOfWork(nextUnitOfwork)}}functionperformUnitOfst(Id}remaining()workLoop)每个fiber都可以看作一个执行单元。在协调过程中,每个更新的纤程都将被视为一个workInProgress。那么workLoop就是执行各个单元的调度器。如果渲染没有中断,那么workLoop会遍历fiber树。performUnitOfWork包括两个阶段:是向下协调的过程,即fiberRoot根据child指针逐层协调。会执行函数组件,实例类组件,diffreconcile子节点是一个向上合并的过程。如果有兄弟节点,则返回兄弟节点。如果不返回parent,则返回fiebrRoot,这样就形成了整棵fiber树。调和。详见前端高级面试题答案import{updateHostComponent}from'./ReactFiberReconciler'functionperformUnitOfWork(wip){//1.更新wipconst{type}=wipif(isStr(type)){//typeisstring,UpdatenormalelementnodeupdateHostComponent(wip)}elseif(isFn(type)){//...}//2.返回下一个要更新的任务深度优先遍历if(wip.child){returnwip.child}letnext=wipwhile(next){if(next.sibling){returnnext.sibling}next=next.return}returnnull}根据类型type,区分为FunctionComponent/ClassComponent/HostComponent/...本文只针对HostComponent类型进行处理,其他类型的处理,完整代码链接见文末。ReactFiberReconciler.jsimport{createFiber}from'./createFiber'exportfunctionupdateHostComponent(wip){if(!wip.stateNode){wip.stateNode=document.createElement(wip.type);updateNode(wip.stateNode,wip.props);}//调和子节点reconcileChildren(wip,wip.props.children);}functionreconcileChildren(returnFiber,children){if(isStr(children)){return}constnewChildren=isArray(children)?孩子们:[孩子们];letpreviousNewFiber=nullfor(leti=0;i
{if(k==="children"){if(isStringOrNumber(nextVal[k])){node.textContent=nextVal[k];}}else{节点[k]=nextVal[k];}});}createFiber.jsexportfunctioncreateFiber(vnode,returnFiber){constnewFiber={type:vnode.type,//标记节点类型key:vnode.key,//标记节点在当前层级props下的唯一性:vnode.props,//属性stateNode:null,//如果组件是原生标签,就是dom节点,如果是类组件,就是类实例child:null,//第一个子节点return:returnFiber,//父节点sibling:null,//下一个兄弟节点};returnnewFiber;}至此render阶段已经完成,下面是commit阶段,commit阶段是基于Fiber结构操作DOMfunctionworkLoop(IdleDeadline){while(nextUnitOfwork&&IdleDeadline.timeRemaining()>0){nextUnitOfwork=performUnitOfWork(nextUnitOfwork)}//提交if(!nextUnitOfwork&&wipRoot){commitRoot();}}functioncommitRoot(){commitWorker(wipRoot.child)wipRoot=null;}functioncommitWorker(wip){if(!wip){return}//1.提交你自己const{stateNode}=wipletparentNode=wip.return.stateNodeif(stateNode){parentNode.appendChild(sta节点);}//2.提交子节点commitWorker(wip.child);//3.提交兄弟节点commitWorker(wip.sibling);}5.总结Fiber结构,Fiber生成过程和reconciliation过程,以及render和commitbigstage。