您好,欢迎来到三六零分类信息网!老站,搜索引擎当天收录,欢迎发信息

React16.2的fiber架构详解

2024/2/29 10:08:24发布23次查看
本文主要和大家分享react16.2的fiber架构详解,希望能帮助到大家。insertupdateintofiber 会根据fiber的状态创建一个或两个列队对象,对象是长成这样的对象是长成这样的
//by 司徒正美, 加群:370262116 一起研究react与anujs // https://github.com/rubylouvre/anu 欢迎加star function createupdatequeue(basestate) {//我们现在是丢了一个null做传参   var queue = {     basestate: basestate,     expirationtime: nowork,//nowork会被立即执行     first: null,     last: null,     callbacklist: null,     hasforceupdate: false,     isinitialized: false   };   return queue; }
schedulework是一个奇怪的方法,只是添加一下参数
 function schedulework(fiber, expirationtime) {     return scheduleworkimpl(fiber, expirationtime, false);   }
scheduleworkimpl的最开头有一个recordscheduleupdate方法,用来记录调度器的执行状态,如注释所示,它现在相当于什么都没有做
function recordscheduleupdate() {   if (enableusertimingapi) {//全局变量,默认为true     if (iscommitting) {//全局变量,默认为false, 没有进入分支       hasscheduledupdateincurrentcommit = true;     }     //全局变量,默认为null,没有没有进入分支     if (currentphase !== null && currentphase !== 'componentwillmount' && currentphase !== 'componentwillreceiveprops') {       hasscheduledupdateincurrentphase = true;     }   } }
scheduleworkimpl的一些分支非常复杂,我们打一些断点
function computeexpirationforfiber(fiber) {     var expirationtime = void 0;     if (expirationcontext !== nowork) {       // an explicit expiration context was set;       expirationtime = expirationcontext;     } else if (isworking) {       if (iscommitting) {         // updates that occur during the commit phase should have sync priority         // by default.         expirationtime = sync;       } else {         // updates during the render phase should expire at the same time as         // the work that is being rendered.         expirationtime = nextrenderexpirationtime;       }     } else {       // no explicit expiration context was set, and we're not currently       // performing work. calculate a new expiration time.       if (usesyncscheduling && !(fiber.internalcontexttag & asyncupdates)) {         // this is a sync update         console.log(expirationtime, sync)         expirationtime = sync;//命中这里       } else {         // this is an async update         expirationtime = computeasyncexpiration();       }     }     return expirationtime;   }     function checkrootneedsclearing(root, fiber, expirationtime) {     if (!isworking && root === nextroot && expirationtime < nextrenderexpirationtime) { console.log("checkrootneedsclearing对nextroot,nextunitofwork,nextrenderexpirationtime进行置空") // restart the root from the top. if (nextunitofwork !== null) { // this is an interruption. (used for performance tracking.) interruptedby = fiber; } nextroot = null; nextunitofwork = null; nextrenderexpirationtime = nowork; }else{ console.log("checkrootneedsclearing就是想酱油") } } function scheduleworkimpl(fiber, expirationtime, iserrorrecovery) { recordscheduleupdate();//现在什么也没做 var node = fiber; while (node !== null) { // walk the parent path to the root and update each node's // expiration time. if (node.expirationtime === nowork || node.expirationtime > expirationtime) {         node.expirationtime = expirationtime;//由于默认就是nowork,因此会被重写 sync       }       if (node.alternate !== null) {//这里进不去         if (node.alternate.expirationtime === nowork || node.alternate.expirationtime > expirationtime) {           node.alternate.expirationtime = expirationtime;         }       }       if (node['return'] === null) {         if (node.tag === hostroot) {//进入这里           var root = node.statenode;           checkrootneedsclearing(root, fiber, expirationtime);           console.log(requestwork,root, expirationtime)           requestwork(root, expirationtime);           checkrootneedsclearing(root, fiber, expirationtime);         } else {           return;         }       }       node = node['return'];     }   }
输出如下
requestwork也很难理解,里面太多全局变量,觉得不是前端的人搞的。为了帮助理解,我们继续加日志
//by 司徒正美, 加群:370262116 一起研究react与anujs  // requestwork is called by the scheduler whenever a root receives an update.   // it's up to the renderer to call renderroot at some point in the future.   /* 只要root收到更新(update对象),requestwork就会被调度程序调用。 渲染器在将来的某个时刻调用renderroot。   */   function requestwork(root, expirationtime) {     if (nestedupdatecount > nested_update_limit) {       invariant_1(false, 'maximum update depth exceeded. this can happen when a component repeatedly calls setstate inside componentwillupdate or componentdidupdate. react limits the number of nested updates to prevent infinite loops.');     }     // add the root to the schedule.     // check if this root is already part of the schedule.     if (root.nextscheduledroot === null) {       // this root is not already scheduled. add it.       console.log(设置remainingexpirationtime,expirationtime)       root.remainingexpirationtime = expirationtime;       if (lastscheduledroot === null) {         console.log(设置firstscheduledroot, lastscheduledroot)         firstscheduledroot = lastscheduledroot = root;         root.nextscheduledroot = root;       } else {         lastscheduledroot.nextscheduledroot = root;         lastscheduledroot = root;         lastscheduledroot.nextscheduledroot = firstscheduledroot;       }     } else {       // this root is already scheduled, but its priority may have increased.       var remainingexpirationtime = root.remainingexpirationtime;       if (remainingexpirationtime === nowork || expirationtime < remainingexpirationtime) { // update the priority. root.remainingexpirationtime = expirationtime; } } if (isrendering) { // prevent reentrancy. remaining work will be scheduled at the end of // the currently rendering batch. return; } if (isbatchingupdates) { // flush work at the end of the batch. if (isunbatchingupdates) { // ...unless we're inside unbatchedupdates, in which case we should // flush it now. nextflushedroot = root; nextflushedexpirationtime = sync; console.log("performworkonroot") performworkonroot(nextflushedroot, nextflushedexpirationtime); } return; } // todo: get rid of sync and use current time? if (expirationtime === sync) { console.log("进入performwork") performwork(sync, null); } else { schedulecallbackwithexpiration(expirationtime); } }
从日志输出来看,requestwork只是修改了两个全局变量,然后进入performwork。这三个内部方法起名很有意思。schedulework意为打算工作,requestwork意为申请工作,performwork意为努力工作(正式上班)
function performwork(minexpirationtime, dl) { deadline = dl; // keep working on roots until there's no more work, or until the we reach // the deadline. //这里会将root设置为highestpriorityroot findhighestpriorityroot(); if (enableusertimingapi && deadline !== null) { var didexpire = nextflushedexpirationtime < recalculatecurrenttime(); console.log(didexpire) stoprequestcallbacktimer(didexpire); } while (nextflushedroot !== null && nextflushedexpirationtime !== nowork && (minexpirationtime === nowork || nextflushedexpirationtime <= minexpirationtime) && !deadlinedidexpire) { console.log("performworkonroot") performworkonroot(highestpriorityroot, nextflushedexpirationtime); // find the next highest priority work. findhighestpriorityroot(); } // we're done flushing work. either we ran out of time in this callback, // or there's no more work left with sufficient priority. // if we're inside a callback, set this to false since we just completed it. if (deadline !== null) { callbackexpirationtime = nowork; callbackid = -1; } // if there's work left over, schedule a new callback. if (nextflushedexpirationtime !== nowork) { console.log("schedulecallbackwithexpiration") schedulecallbackwithexpiration(nextflushedexpirationtime); } // clean-up. deadline = null; deadlinedidexpire = false; nestedupdatecount = 0; if (hasunhandlederror) { //如果有没处理的错误则throw var _error4 = unhandlederror; unhandlederror = null; hasunhandlederror = false; throw _error4; } }
我们终于进入performworkonroot,performworkonroot的作用是区分同步渲染还是异步渲染,expirationtime等于1,因此进入同步。导步肯定为false
// https://github.com/rubylouvre/anu 欢迎加star function performworkonroot(root, expirationtime) { isrendering = true; // check if this is async work or sync/expired work. // todo: pass current time as argument to renderroot, commitroot if (expirationtime <= recalculatecurrenttime()) { // flush sync work. var finishedwork = root.finishedwork; console.log("flush sync work.", finishedwork) if (finishedwork !== null) { // this root is already complete. we can commit it. root.finishedwork = null; console.log("commitroot") root.remainingexpirationtime = commitroot(finishedwork); } else { root.finishedwork = null; console.log("renderroot") finishedwork = renderroot(root, expirationtime); if (finishedwork !== null) { console.log("继续commitroot") // we've completed the root. commit it. root.remainingexpirationtime = commitroot(finishedwork); } } } else { console.log("flush async work.") // flush async work. // ...略 } isrendering = false; }
renderroot也是怒长,react16代码的特点是许多巨型类,巨型方法,有java之遗风。renderroot只有前面几行是可能处理虚拟dom(或叫fiber),后面都是错误边界的
function renderroot(root, expirationtime) { isworking = true; // we're about to mutate the work-in-progress tree. if the root was pending // commit, it no longer is: we'll need to complete it again. root.isreadyforcommit = false; // check if we're starting from a fresh stack, or if we're resuming from // previously yielded work. if (root !== nextroot || expirationtime !== nextrenderexpirationtime || nextunitofwork === null) { // reset the stack and start working from the root. resetcontextstack(); nextroot = root; nextrenderexpirationtime = expirationtime; //可能是用来工作的代码 console.log("createworkinprogress") nextunitofwork = createworkinprogress(nextroot.current, null, expirationtime); } //可能是用来工作的代码 console.log("startworklooptimer") startworklooptimer(nextunitofwork); // 处理错误边界 var diderror = false; var error = null; invokeguardedcallback$1(null, workloop, null, expirationtime); // an error was thrown during the render phase. while (diderror) { console.log("componentdidcatch的相关实现") if (didfatal) { // this was a fatal error. don't attempt to recover from it. firstuncaughterror = error; break; } var failedwork = nextunitofwork; if (failedwork === null) { // an error was thrown but there's no current unit of work. this can // happen during the commit phase if there's a bug in the renderer. didfatal = true; continue; } // 处理错误边界 var boundary = captureerror(failedwork, error); !(boundary !== null) ? invariant_1(false, 'should have found an error boundary. this error is likely caused by a bug in react. please file an issue.') : void 0; if (didfatal) { // the error we just captured was a fatal error. this happens // when the error propagates to the root more than once. continue; } // 处理错误边界 diderror = false; error = null; // we're finished working. exit the error loop. break; } // 处理错误边界 var uncaughterror = firstuncaughterror; // we're done performing work. time to clean up. stopworklooptimer(interruptedby); interruptedby = null; isworking = false; didfatal = false; firstuncaughterror = null; // 处理错误边界 if (uncaughterror !== null) { onuncaughterror(uncaughterror); } return root.isreadyforcommit ? root.current.alternate : null; } function resetcontextstack() { // reset the stack reset$1(); // reset the cursors resetcontext(); resethostcontainer(); } function reset$1() { console.log("reset",index) while (index > -1) {     valuestack[index] = null;     {       fiberstack[index] = null;     }     index--;   } } function resetcontext() {   consoel.log(resetcontext)   previouscontext = emptyobject_1;   contextstackcursor.current = emptyobject_1;   didperformworkstackcursor.current = false; }   function resethostcontainer() {     console.log(resethostcontainer,contextstackcursor, rootinstancestackcursor, no_context )     contextstackcursor.current = no_context;     rootinstancestackcursor.current = no_context;   }
createworkinprogress就是将根组件的fiber对象再复制一份,变成其alternate属性。因此 将虚拟dom转换为真实dom的重任就交给invokeguardedcallback
var invokeguardedcallback = function (name, func, context, a, b, c, d, e, f) {   reacterrorutils._hascaughterror = false;   reacterrorutils._caughterror = null;   var funcargs = array.prototype.slice.call(arguments, 3);   try {     func.apply(context, funcargs);   } catch (error) {     reacterrorutils._caughterror = error;     reacterrorutils._hascaughterror = true;   } //这下面还有怒长(100-150l )的关于错误边界的处理,略过 };
func为workloop
//by 司徒正美, 加群:370262116 一起研究react与anujs  function workloop(expirationtime) {     if (capturederrors !== null) {       // if there are unhandled errors, switch to the slow work loop.       // todo: how to avoid this check in the fast path? maybe the renderer       // could keep track of which roots have unhandled errors and call a       // forked version of renderroot.       slowworkloopthatchecksforfailedwork(expirationtime);       return;     }     if (nextrenderexpirationtime === nowork || nextrenderexpirationtime > expirationtime) {       return;     }     if (nextrenderexpirationtime <= mostrecentcurrenttime) { // flush all expired work. while (nextunitofwork !== null) { console.log("performunitofwork",nextunitofwork) nextunitofwork = performunitofwork(nextunitofwork); } } else { // flush asynchronous work until the deadline runs out of time. while (nextunitofwork !== null && !shouldyield()) { nextunitofwork = performunitofwork(nextunitofwork); } } }
我们终于看到工作的代码了。 这个nextunitofwork 是renderroot生成的
performunitofwork与beginwork的代码,里面会根据fiber的tag进入各种操作
//by 司徒正美, 加群:370262116 一起研究react与anujs // https://github.com/rubylouvre/anu 欢迎加star function performunitofwork(workinprogress) { // the current, flushed, state of this fiber is the alternate. // ideally nothing should rely on this, but relying on it here // means that we don't need an additional field on the work in // progress. var current = workinprogress.alternate; // see if beginning this work spawns more work. startworktimer(workinprogress); { reactdebugcurrentfiber.setcurrentfiber(workinprogress); } console.log("beginwork") var next = beginwork(current, workinprogress, nextrenderexpirationtime); { reactdebugcurrentfiber.resetcurrentfiber(); } if (true && reactfiberinstrumentation_1.debugtool) { reactfiberinstrumentation_1.debugtool.onbeginwork(workinprogress); } if (next === null) { console.log("next") // if this doesn't spawn new work, complete the current work. next = completeunitofwork(workinprogress); } reactcurrentowner.current = null; return next; } function beginwork(current, workinprogress, renderexpirationtime) { if (workinprogress.expirationtime === nowork || workinprogress.expirationtime > renderexpirationtime) {       return bailoutonlowpriority(current, workinprogress);     }     switch (workinprogress.tag) {       case indeterminatecomponent:         return mountindeterminatecomponent(current, workinprogress, renderexpirationtime);       case functionalcomponent:         return updatefunctionalcomponent(current, workinprogress);       case classcomponent:         return updateclasscomponent(current, workinprogress, renderexpirationtime);       case hostroot:         return updatehostroot(current, workinprogress, renderexpirationtime);       case hostcomponent:         return updatehostcomponent(current, workinprogress, renderexpirationtime);       case hosttext:         return updatehosttext(current, workinprogress);       case callhandlerphase:         // this is a restart. reset the tag to the initial phase.         workinprogress.tag = callcomponent;       // intentionally fall through since this is now the same.       case callcomponent:         return updatecallcomponent(current, workinprogress, renderexpirationtime);       case returncomponent:         // a return component is just a placeholder, we can just run through the         // next one immediately.         return null;       case hostportal:         return updateportalcomponent(current, workinprogress, renderexpirationtime);       case fragment:         return updatefragment(current, workinprogress);       default:         invariant_1(false, 'unknown unit of work tag. this error is likely caused by a bug in react. please file an issue.');     }   }
我们再调查一下workinprogress.tag是什么
https://github.com/facebook/r...
这里有全部fiber节点的类型描述,我们创建一个对象
// https://github.com/rubylouvre/anu 欢迎加star var mapbeginwork = {     3: hostroot 根组件,     0: indeterminatecomponent 只知道type为函数,     2: classcomponent 普通类组件 ,     5: hostcomponent 元素节点,     6: hosttext 文本节点   }   function beginwork(current, workinprogress, renderexpirationtime) {     if (workinprogress.expirationtime === nowork || workinprogress.expirationtime > renderexpirationtime) {       return bailoutonlowpriority(current, workinprogress);     }     console.log(workinprogress.tag, mapbeginwork[workinprogress.tag])      switch (workinprogress.tag) {      //略      } }
相关推荐:
nodejs中的fiber(纤程)库详解_node.js
以上就是react16.2的fiber架构详解的详细内容。
该用户其它信息

VIP推荐

免费发布信息,免费发布B2B信息网站平台 - 三六零分类信息网 沪ICP备09012988号-2
企业名录 Product