这次是接着上一期render阶段的文章,解析挂载时render阶段的"归"阶段----completeWork函数

completeWork开始阶段

在performUnitOfWork中执行完beginWork,就会进入上面判断

  if (next === null) {    // workInProgress曾经不存在子树,就开始进行"归"阶段    completeUnitOfWork(unitOfWork);  } else {    // next是beginWork调用后的返回值workInProgress.child    workInProgress = next;  }

completeUnitOfWork

次要做了两件事,执行completeWork 和收拢EffectList

function completeUnitOfWork(unitOfWork: Fiber): void {  //尝试实现以后的工作单元,而后挪动到下一个兄弟。 如果没有更多的兄弟,返回到父fiber。  let completedWork = unitOfWork;  // 直到父节点为null,示意整棵 workInProgress fiber 树已处理完毕。  do {    // 记录父节点和以后节点的current树    const current = completedWork.alternate;    const returnFiber = completedWork.return;    // 查看工作是否实现或是否有货色抛出.    if ((completedWork.effectTag & Incomplete) === NoEffect) {      let next;      if (        !enableProfilerTimer ||        (completedWork.mode & ProfileMode) === NoMode      ) {        // 执行completeWork,并把返回值赋值给next        next = completeWork(current, completedWork, subtreeRenderLanes);      } else {        startProfilerTimer(completedWork);        next = completeWork(current, completedWork, subtreeRenderLanes);        // Update render duration assuming we didn't error.        stopProfilerTimerIfRunningAndRecordDelta(completedWork, false);      }      resetCurrentDebugFiberInDEV();      if (next !== null) {        // Completing this fiber spawned new work. Work on that next.        workInProgress = next;        return;      }      resetChildLanes(completedWork);      if (        returnFiber !== null &&        (returnFiber.effectTag & Incomplete) === NoEffect      ) {        // 执行effect相干        if (returnFiber.firstEffect === null) {          returnFiber.firstEffect = completedWork.firstEffect;        }        if (completedWork.lastEffect !== null) {          if (returnFiber.lastEffect !== null) {            returnFiber.lastEffect.nextEffect = completedWork.firstEffect;          }          returnFiber.lastEffect = completedWork.lastEffect;        }        if (effectTag > PerformedWork) {          if (returnFiber.lastEffect !== null) {            returnFiber.lastEffect.nextEffect = completedWork;          } else {            returnFiber.firstEffect = completedWork;          }          returnFiber.lastEffect = completedWork;        }      }    } else {      const next = unwindWork(completedWork, subtreeRenderLanes);      // Because this fiber did not complete, don't reset its expiration time.      if (next !== null) {        next.effectTag &= HostEffectMask;        workInProgress = next;        return;      }      if (        enableProfilerTimer &&        (completedWork.mode & ProfileMode) !== NoMode      ) {               stopProfilerTimerIfRunningAndRecordDelta(completedWork, false);        let actualDuration = completedWork.actualDuration;        let child = completedWork.child;        while (child !== null) {          actualDuration += child.actualDuration;          child = child.sibling;        }        completedWork.actualDuration = actualDuration;      }      if (returnFiber !== null) {        // Mark the parent fiber as incomplete and clear its effect list.        returnFiber.firstEffect = returnFiber.lastEffect = null;        returnFiber.effectTag |= Incomplete;      }    }    const siblingFiber = completedWork.sibling;    if (siblingFiber !== null) {      // If there is more work to do in this returnFiber, do that next.      workInProgress = siblingFiber;      return;    }    // 赋值父节点    completedWork = returnFiber;    workInProgress = completedWork;  } while (completedWork !== null);  // We've reached the root.  if (workInProgressRootExitStatus === RootIncomplete) {    workInProgressRootExitStatus = RootCompleted;  }}

运行流程

completeWork

如果说“递”阶段的 beginWork 办法次要是创立子节点,那么“归”阶段的 completeWork 办法则次要是创立以后节点的 DOM 节点,并对子节点的 DOM 节点和 EffectList 进行收拢。很多类型是不进行解决,return null

function completeWork(  current: Fiber | null,  workInProgress: Fiber,  renderLanes: Lanes,): Fiber | null {  const newProps = workInProgress.pendingProps;  switch (workInProgress.tag) {    case IndeterminateComponent:    case LazyComponent:    case SimpleMemoComponent:    case FunctionComponent:    case ForwardRef:    case Fragment:    case Mode:    case Profiler:    case ContextConsumer:    case MemoComponent:      return null;    case ClassComponent: {      // ...省略      return null;    }    case HostRoot: {      // ...省略      return null;    }    case HostComponent: {      // ...      const type = workInProgress.type;      if (current !== null && workInProgress.stateNode != null) {      //更新dom节点        updateHostComponent(          current,          workInProgress,          type,          newProps,          rootContainerInstance,        );        if (enableDeprecatedFlareAPI) {          const prevListeners = current.memoizedProps.DEPRECATED_flareListeners;          const nextListeners = newProps.DEPRECATED_flareListeners;          if (prevListeners !== nextListeners) {            markUpdate(workInProgress);          }        }        if (current.ref !== workInProgress.ref) {          markRef(workInProgress);        }      } else {        //...        const currentHostContext = getHostContext();        const wasHydrated = popHydrationState(workInProgress);        if (wasHydrated) {          // 服务端渲染相干        } else {          // 创立新的dom节点          const instance = createInstance(            type,            newProps,            rootContainerInstance,            currentHostContext,            workInProgress,          );          // 把fiber子节点的dom挂载到以后dom前面          appendAllChildren(instance, workInProgress, false, false);          workInProgress.stateNode = instance;          if (enableDeprecatedFlareAPI) {            const listeners = newProps.DEPRECATED_flareListeners;            if (listeners != null) {              updateDeprecatedEventListeners(                listeners,                workInProgress,                rootContainerInstance,              );            }          }          if (            // 初始化dom属性和事件            finalizeInitialChildren(              instance,              type,              newProps,              rootContainerInstance,              currentHostContext,            )          ) {            markUpdate(workInProgress);          }        }        if (workInProgress.ref !== null) {          markRef(workInProgress);        }      }      return null;    }  // ...省略}

createInstance

新建节点,调用createElement创立dom节点

function createInstance(  type: string,  props: Props,  rootContainerInstance: Container,  hostContext: HostContext,  internalInstanceHandle: Object,): Instance {  let parentNamespace: string;  if (__DEV__) {    // TODO: take namespace into account when validating.    const hostContextDev = ((hostContext: any): HostContextDev);    validateDOMNesting(type, null, hostContextDev.ancestorInfo);    if (      typeof props.children === 'string' ||      typeof props.children === 'number'    ) {      const string = '' + props.children;      const ownAncestorInfo = updatedAncestorInfo(        hostContextDev.ancestorInfo,        type,      );      validateDOMNesting(null, string, ownAncestorInfo);    }    parentNamespace = hostContextDev.namespace;  } else {    parentNamespace = ((hostContext: any): HostContextProd);  }  const domElement: Instance = createElement(    type,    props,    rootContainerInstance,    parentNamespace,  );  precacheFiberNode(internalInstanceHandle, domElement);  // 更新属性  updateFiberProps(domElement, props);  return domElement;}

appendAllChildren

把fiber子节点的dom挂载到以后dom前面

 appendAllChildren = function(    parent: Instance,    workInProgress: Fiber,    needsVisibilityToggle: boolean,    isHidden: boolean,  ) {    let node = workInProgress.child;    while (node !== null) {      if (node.tag === HostComponent || node.tag === HostText) {        // stateNode挂载节点的dom        appendInitialChild(parent, node.stateNode);      } else if (enableFundamentalAPI && node.tag === FundamentalComponent) {        appendInitialChild(parent, node.stateNode.instance);      } else if (node.tag === HostPortal) {      } else if (node.child !== null) {        // 针对一些非凡类型的子节点,如<Fragment />,尝试从子节点的子节点获取DOM        // 存在子节点就持续遍历子节点        node.child.return = node;        node = node.child;        continue;      }      if (node === workInProgress) {        return;      }      while (node.sibling === null) {        if (node.return === null || node.return === workInProgress) {          return;        }        node = node.return;      }      node.sibling.return = node.return;      // 将node.sibling作为下次循环的主体      node = node.sibling;    }  };// 执行了原生的appendChild办法export function appendInitialChild(parentInstance: Instance, child: Instance | TextInstance): void {  parentInstance.appendChild(child);}

updateHostComponent

更新旧的dom节点,次要作用就是计算出须要变动的 DOM 节点属性,并给以后节点打上Update的EffectTag。

updateHostComponent = function(    current: Fiber,    workInProgress: Fiber,    type: Type,    newProps: Props,    rootContainerInstance: Container,  ) {    // If we have an alternate, that means this is an update and we need to    // schedule a side-effect to do the updates.    const oldProps = current.memoizedProps;    // props没有变动就间接返回    if (oldProps === newProps) {      return;    }        const updatePayload = prepareUpdate(      instance,      type,      oldProps,      newProps,      rootContainerInstance,      currentHostContext,    );    // 将计算出来的updatePayload挂载在workInProgress.updateQueue上,供后续commit阶段应用    workInProgress.updateQueue = (updatePayload: any);    // 如果updatePayload不为空,则给以后节点打上Update的EffectTag    if (updatePayload) {      markUpdate(workInProgress);    }  };

总结

  1. completeUnitOfWork办法次要循环执行completeWork,父元素为空或者存在兄弟节点就会进行下一轮render阶段解析,生成兄弟节点的fiber。
  2. completeWork次要是生成以后fiber的dom节点,并且挂载连接子节点的dom
  3. completeWork次要应用createInstance新建节点和updateHostComponent更新节点操作。
  4. 最终完结completeUnitOfWork执行,进入commit阶段(下个文章开始讲,敬请期待)