初窥React-7(updateContainer方法-p2)

来到了update入栈了 enqueueUpdate(current$1, update);
function enqueueUpdate(fiber, update) { 
    var updateQueue = fiber.updateQueue; //取出当前的updateQueue

    if (updateQueue === null) {
      // Only occurs if the fiber has been unmounted.
      return;
    }

    var sharedQueue = updateQueue.shared;
    var pending = sharedQueue.pending;                

    //update插入到fiber的updateQueue.shared队列当中...
    if (pending === null) {
      // This is the first update. Create a circular list.
      update.next = update;
    } else {
      //入队 c- > a b之间
      update.next = pending.next;
      pending.next = update;
    }

    sharedQueue.pending = update;

    {
      if (currentlyProcessingQueue === sharedQueue && !didWarnUpdateInsideUpdate) {
        error('An update (setState, replaceState, or forceUpdate) was scheduled ' + 'from inside an update function. Update functions should be pure, ' + 'with zero side-effects. Consider using componentDidUpdate or a ' + 'callback.');

        didWarnUpdateInsideUpdate = true;
      }
    }
  }

 

update对象创建完成后意味着需要对页面进行更新,会调用scheduleUpdateOnFiber进入调度
scheduleUpdateOnFiber(current$1, lane, eventTime);
function scheduleUpdateOnFiber(fiber, lane, eventTime) {
    checkForNestedUpdates();
    warnAboutRenderPhaseUpdatesInDEV(fiber);
    var root = markUpdateLaneFromFiberToRoot(fiber, lane);

    if (root === null) {
      warnAboutUpdateOnUnmountedFiberInDEV(fiber);
      return null;
    } // Mark that the root has a pending update.


    markRootUpdated(root, lane, eventTime);

    if (root === workInProgressRoot) {
      // Received an update to a tree that's in the middle of rendering. Mark
      // that there was an interleaved update work on this root. Unless the
      // `deferRenderPhaseUpdateToNextBatch` flag is off and this is a render
      // phase update. In that case, we don't treat render phase updates as if
      // they were interleaved, for backwards compat reasons.
      {
        workInProgressRootUpdatedLanes = mergeLanes(workInProgressRootUpdatedLanes, lane);
      }

      if (workInProgressRootExitStatus === RootSuspendedWithDelay) {
        // The root already suspended with a delay, which means this render
        // definitely won't finish. Since we have a new update, let's mark it as
        // suspended now, right before marking the incoming update. This has the
        // effect of interrupting the current render and switching to the update.
        // TODO: Make sure this doesn't override pings that happen while we've
        // already started rendering.
        markRootSuspended$1(root, workInProgressRootRenderLanes);
      }
    } // TODO: requestUpdateLanePriority also reads the priority. Pass the
    // priority as an argument to that function and this one.

  
    var priorityLevel = getCurrentPriorityLevel();

    if (lane === SyncLane) { //SyncLane 情况下,判断是否处在unbatched并且Render和Commit阶段
      if ( // Check if we're inside unbatchedUpdates
      (executionContext & LegacyUnbatchedContext) !== NoContext && // Check if we're not already rendering
      (executionContext & (RenderContext | CommitContext)) === NoContext) {
        // Register pending interactions on the root to avoid losing traced interaction data.
        schedulePendingInteractions(root, lane); // This is a legacy edge case. The initial mount of a ReactDOM.render-ed
        // root inside of batchedUpdates should be synchronous, but layout updates
        // should be deferred until the end of the batch.

        performSyncWorkOnRoot(root);//比较重要其他篇幅会介绍,里面是render过程
      } else {
        ensureRootIsScheduled(root, eventTime);//比较重要其他篇幅会介绍,调度决策逻辑,任务优先级在即将调度的时候会被计算
        schedulePendingInteractions(root, lane);

        if (executionContext === NoContext) {
          // Flush the synchronous work now, unless we're already working or inside
          // a batch. This is intentionally inside scheduleUpdateOnFiber instead of
          // scheduleCallbackForFiber to preserve the ability to schedule a callback
          // without immediately flushing it. We only do this for user-initiated
          // updates, to preserve historical behavior of legacy mode.
          resetRenderTimer();
          flushSyncCallbackQueue();
        }
      }
    } else { //处理非Sync的场景
      // Schedule a discrete update but only if it's not Sync.
      if ((executionContext & DiscreteEventContext) !== NoContext && ( // Only updates at user-blocking priority or greater are considered
      // discrete, even inside a discrete event.
      priorityLevel === UserBlockingPriority$2 || priorityLevel === ImmediatePriority$1)) {
        // This is the result of a discrete event. Track the lowest priority
        // discrete update per root so we can flush them early, if needed.
        if (rootsWithPendingDiscreteUpdates === null) {
          rootsWithPendingDiscreteUpdates = new Set([root]);
        } else {
          rootsWithPendingDiscreteUpdates.add(root);
        }
      } // Schedule other updates after in case the callback is sync.


      ensureRootIsScheduled(root, eventTime);
      schedulePendingInteractions(root, lane);
    } // We use this when assigning a lane for a transition inside
    // `requestUpdateLane`. We assume it's the same as the root being updated,
    // since in the common case of a single root app it probably is. If it's not
    // the same root, then it's not a huge deal, we just might batch more stuff
    // together more than necessary.


    mostRecentlyUpdatedRoot = root;
  }

两种模式的不同点:

  1. createRootImpl中传入的第二个参数不一样 一个是LegacyRoot一个是ConcurrentRoot
  2. requestUpdateLane中获取的lane的优先级不同
  3. 在函数scheduleUpdateOnFiber中根据不同优先级进入不同分支,legacy模式进入performSyncWorkOnRoot,concurrent模式会异步调度performConcurrentWorkOnRoot
 
  // This is split into a separate function so we can mark a fiber with pending
  // work without treating it as a typical update that originates from an event;
  // e.g. retrying a Suspense boundary isn't an update, but it does schedule work
  // on a fiber.
 //​ 在markUpdateLaneFromFiberToRoot函数中会从触发更新的节点开始向上遍历到rootFiber,遍历的过程会处理节点的优先级
  function markUpdateLaneFromFiberToRoot(sourceFiber, lane) {
    // Update the source fiber's lanes
    sourceFiber.lanes = mergeLanes(sourceFiber.lanes, lane);
    var alternate = sourceFiber.alternate;

    if (alternate !== null) {
      alternate.lanes = mergeLanes(alternate.lanes, lane);
    }

    {
      if (alternate === null && (sourceFiber.flags & (Placement | Hydrating)) !== NoFlags) {
        warnAboutUpdateOnNotYetMountedFiberInDEV(sourceFiber);
      }
    } // Walk the parent path to the root and update the child expiration time.


    var node = sourceFiber;
    var parent = sourceFiber.return;

    while (parent !== null) {
      parent.childLanes = mergeLanes(parent.childLanes, lane);//更新parent的childLanes
      alternate = parent.alternate; //alternate指向parent.alternate

      if (alternate !== null) {
        alternate.childLanes = mergeLanes(alternate.childLanes, lane); //更新parent.alternate的childLanes.
      } else {
        {
          if ((parent.flags & (Placement | Hydrating)) !== NoFlags) {
            warnAboutUpdateOnNotYetMountedFiberInDEV(sourceFiber);
          }
        }
      }
    
      node = parent; //继续向上遍历
      parent = parent.return;
    }

    if (node.tag === HostRoot) {
      var root = node.stateNode;
      return root;
    } else {
      return null;
    }
  }

 

function markRootUpdated(root, updateLane, eventTime) {
    root.pendingLanes |= updateLane; 

// TODO: Theoretically, any update to any lane can unblock any other lane. But // it's not practical to try every single possible combination. We need a // heuristic to decide which lanes to attempt to render, and in which batches. // For now, we use the same heuristic as in the old ExpirationTimes model: // retry any lane at equal or lower priority, but don't try updates at higher // priority without also including the lower priority updates. This works well // when considering updates across different priority levels, but isn't // sufficient for updates within the same priority, since we want to treat // those updates as parallel. // Unsuspend any update at equal or lower priority. var higherPriorityLanes = updateLane - 1; // Turns 0b1000 into 0b0111 root.suspendedLanes &= higherPriorityLanes; root.pingedLanes &= higherPriorityLanes; var eventTimes = root.eventTimes; var index = laneToIndex(updateLane); // We can always overwrite an existing timestamp because we prefer the most // recent event, and we assume time is monotonically increasing. eventTimes[index] = eventTime; }

 

 

上一节  下一节

posted @ 2021-07-08 23:27  AllenLiu0927  阅读(144)  评论(0编辑  收藏  举报