工作流程总览
Scheduler
根据任务优先级调度任务,render阶段如果浏览器有其它高优先级,会暂停render,去执行别的任务,完成后再继续执行render,会从上次执行暂停的fiber节点位置继续执行
render
Reconciler(diff)阶段,
初始mount拿到虚拟dom,递归遍历虚拟dom,生成fiber链表结构数据。
更新阶段递归遍历fiber树,查找到更新部分,做标记,更新完成的fiber树交给commit阶段处理
commit
根据fiber节点,将需要更新的dom渲染到浏览器中。这一步是同步执行
原生标签渲染
ReactDOM.render(
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>,
document.getElementById('root')
)
// 经过babel处理之后
ReactDOM.render(
/*#__PURE__*/ React.createElement(
"ul",
null,
/*#__PURE__*/ React.createElement("li", null, "1"),
/*#__PURE__*/ React.createElement("li", null, "2"),
/*#__PURE__*/ React.createElement("li", null, "3")
),
document.getElementById("root")
);
React.createElement返回的是虚拟dom结构,结构如下
ul经过加工生成的fiber结构如下
child
li经过加工生成如下
sibling
return
函数式组件渲染
const Test = () => {
return <ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
}
ReactDOM.render(
<Test/>,
document.getElementById('root')
)
// bable处理之后
const Test = () => {
return /*#__PURE__*/ React.createElement(
"ul",
null,
/*#__PURE__*/ React.createElement("li", null, "1"),
/*#__PURE__*/ React.createElement("li", null, "2"),
/*#__PURE__*/ React.createElement("li", null, "3")
);
};
ReactDOM.render(
/*#__PURE__*/ React.createElement(Test, null),
document.getElementById("root")
);
组件虚拟dom返回结构如下
Test组件Filber
\
child
ul的Fiber结构
同上面原生标签的fiber结构
fiber数据结构
flags
标记节点在commit阶段需要的处理,删除还是替换还是不动
type
div、ul等原生标签、类组件、函数组件
child
当前节点的第一个子节点
Sibling
当前节点的右侧一个兄弟组件
Return
当前节点的父节点
tag
当前节点的类型,后面会针对不同的tag做不同的mout和update处理
var FunctionComponent = 0;
var ClassComponent = 1;
var IndeterminateComponent = 2; // Before we know whether it is function or class
var HostRoot = 3; // Root of a host tree. Could be nested inside another node.
var HostPortal = 4; // A subtree. Could be an entry point to a different renderer.
var HostComponent = 5;
var HostText = 6;
var Fragment = 7;
var Mode = 8;
var ContextConsumer = 9;
var ContextProvider = 10;
var ForwardRef = 11;
var Profiler = 12;
var SuspenseComponent = 13;
var MemoComponent = 14;
var SimpleMemoComponent = 15;
var LazyComponent = 16;
var IncompleteClassComponent = 17;
var DehydratedFragment = 18;
var SuspenseListComponent = 19;
var FundamentalComponent = 20;
var ScopeComponent = 21;
var Block = 22;
var OffscreenComponent = 23;
var LegacyHiddenComponent = 24;
Alternate
主要对应源码中的workInProgress和current,当前的fiber节点和工作中的fiber节点,两者使用该属性互相引用
fiber工作伪代码
网上找的fiber工作伪代码,能直观看得到它的整个工作流程
html结构
<a1>
<b1></b1>
<b2>
<c1>
<d1></d1>
<d2></d2>
</c1>
</b2>
<b3>
<c2></c2>
</b3>
</a1>
处理成fiber结构
const a1 = { name: 'a1', child: null, sibling: null, return: null };
const b1 = { name: 'b1', child: null, sibling: null, return: null };
const b2 = { name: 'b2', child: null, sibling: null, return: null };
const b3 = { name: 'b3', child: null, sibling: null, return: null };
const c1 = { name: 'c1', child: null, sibling: null, return: null };
const c2 = { name: 'c2', child: null, sibling: null, return: null };
const d1 = { name: 'd1', child: null, sibling: null, return: null };
const d2 = { name: 'd2', child: null, sibling: null, return: null };
a1.child = b1;
b1.sibling = b2;
b2.sibling = b3;
b2.child = c1;
b3.child = c2;
c1.child = d1;
d1.sibling = d2;
b1.return = b2.return = b3.return = a1;
c1.return = b2;
d1.return = d2.return = c1;
c2.return = b3;
let nextUnitOfWork = a1;
// 循环遍历fiber树
workLoop();
function workLoop() {
while (nextUnitOfWork !== null) {
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
}
}
// 执行一个工作单元,以一个fiber节点为一个unit
function performUnitOfWork(workInProgress) {
let next = beginWork(workInProgress);
if (next === null) {
next = completeUnitOfWork(workInProgress);
}
return next;
}
//
function beginWork(workInProgress) {
log('work performed for ' + workInProgress.name);
return workInProgress.child;
}
function completeUnitOfWork(workInProgress) {
while (true) {
let returnFiber = workInProgress.return;
let siblingFiber = workInProgress.sibling;
// 完成本次节点
nextUnitOfWork = completeWork(workInProgress);
// 如果有兄弟元素,将兄弟元素返回,赋值next
if (siblingFiber !== null) {
return siblingFiber;
} else if (returnFiber !== null) { // 如果没有兄弟元素,结束每次循环,回到父级节点查找兄弟节点
workInProgress = returnFiber;
continue;
} else { // 没有父节点和兄弟节点,返回null,结束递归,commit到到
return null;
}
}
}
function completeWork(workInProgress) {
log('work completed for ' + workInProgress.name);
return null;
}
function log(message) {
let node = document.createElement('div');
node.textContent = message;
document.body.appendChild(node);
}
执行过程
work begin for a1
work begin for b1
work completed for b1
work begin for b2
work begin for c1
work begin for d1
work completed for d1
work begin for d2
work completed for d2
work completed for c1
work completed for b2
work begin for b3
work begin for c2
work completed for c2
work completed for b3
work completed for a1
对应源码
// workInProgress使用全局变量处理
function workLoopSync() {
// Already timed out, so perform work without checking if we need to yield.
while (workInProgress !== null) {
// console.log(workInProgress, "workInProgress")
performUnitOfWork(workInProgress);
}
}
function performUnitOfWork(unitOfWork) {
// 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 = unitOfWork.alternate;
setCurrentFiber(unitOfWork);
var next;
if ( (unitOfWork.mode & ProfileMode) !== NoMode) {
startProfilerTimer(unitOfWork);
next = beginWork$1(current, unitOfWork, subtreeRenderLanes);
stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true);
} else {
next = beginWork$1(current, unitOfWork, subtreeRenderLanes);
}
resetCurrentFiber();
unitOfWork.memoizedProps = unitOfWork.pendingProps;
if (next === null) {
// If this doesn't spawn new work, complete the current work.
completeUnitOfWork(unitOfWork);
} else {
workInProgress = next;
}
ReactCurrentOwner$2.current = null;
}
beginWork
会返回当前节点的第一个子节点child,没有则返回null,后面会赋值给workInProgress
function beginWork(current, workInProgress, renderLanes) {
...其它优化逻辑
// 根据不同tag做不同处理
switch (workInProgress.tag) {
case IndeterminateComponent:
{
return mountIndeterminateComponent(current, workInProgress, workInProgress.type, renderLanes);
}
...其它case
case FunctionComponent:
{
var _Component = workInProgress.type;
var unresolvedProps = workInProgress.pendingProps;
var resolvedProps = workInProgress.elementType === _Component ? unresolvedProps : resolveDefaultProps(_Component, unresolvedProps);
return updateFunctionComponent(current, workInProgress, _Component, resolvedProps, renderLanes);
}
...其它case
}
}
completeUnitOfWork
beginWork如果没有返回child,发返回null,这里会去找父级兄弟节点,并把将兄弟节点赋值给workInProgress