1. Core knowledge points

Date.now () -nextFrame (the next time the requestAnimation will execute the rub)

Loop render root’s condition

Asynchronous work passes the processing of the elapsed time slice back to the browser for execution

2.performAsyncWork performsyncWork performwork

/ /! Find the root of the highest priority in root list assigned to nextFlushedRoot and nextFlushedExpirationTimes attributes
function findHighestPriorityRoot() {
  let highestPriorityWork = NoWork;
  let highestPriorityRoot = null;
  if(lastScheduledRoot ! = =null) {
    let previousScheduledRoot = lastScheduledRoot;
    let root = firstScheduledRoot;
    while(root ! = =null) {/ /! Loop to find the root with the highest priority
      const remainingExpirationTime = root.expirationTime;
      if (remainingExpirationTime === NoWork) {//!这个root没有任何跟新 那么删除这个root 下面四个if都是删除root
        // This root no longer has work. Remove it from the scheduler.

        // TODO: This check is redudant, but Flow is confused by the branch
        // below where we set lastScheduledRoot to null, even though we break
        // from the loop right after.invariant( previousScheduledRoot ! = =null&& lastScheduledRoot ! = =null.'Should have a previous and last root. This error is likely ' +
            'caused by a bug in React. Please file an issue.',);if (root === root.nextScheduledRoot) {/ /! The entire application has only one root and is not updated
          // This is the only root in the list.
          root.nextScheduledRoot = null;
          firstScheduledRoot = lastScheduledRoot = null;
          break;
        } else if (root === firstScheduledRoot) {/ /! The first one
          // This is the first root in the list.
          const next = root.nextScheduledRoot;
          firstScheduledRoot = next;
          lastScheduledRoot.nextScheduledRoot = next;
          root.nextScheduledRoot = null;
        } else if (root === lastScheduledRoot) {/ /! The last one
          // This is the last root in the list.
          lastScheduledRoot = previousScheduledRoot;
          lastScheduledRoot.nextScheduledRoot = firstScheduledRoot;
          root.nextScheduledRoot = null;
          break;
        } else {/ /! In the middle
          previousScheduledRoot.nextScheduledRoot = root.nextScheduledRoot;
          root.nextScheduledRoot = null;
        }
        root = previousScheduledRoot.nextScheduledRoot;
      } else {
        / /! The root has been updated
        if (
          highestPriorityWork === NoWork ||
          remainingExpirationTime < highestPriorityWork
        ) {
          // Update the priority, if it's higher
          highestPriorityWork = remainingExpirationTime;
          highestPriorityRoot = root;
        }
        if (root === lastScheduledRoot) {
          break;
        }
        if (highestPriorityWork === Sync) {
          // Sync is highest priority by definition so
          // we can stop searching.
          break;
        }
        previousScheduledRoot = root;
        root = root.nextScheduledRoot;
      }
    }
  }

  nextFlushedRoot = highestPriorityRoot;
  nextFlushedExpirationTime = highestPriorityWork;
}

function performAsyncWork(dl) {/ /! This is a function that is scheduled by schedule to be executed in idle time. Dl is dealine and has two properties called Timeremaining and didTimeout
  if (dl.didTimeout) {/ /! overdue
    // The callback timed out. That means at least one update has expired.
    // Iterate through the root schedule. If they contain expired work, set
    // the next render expiration time to the current time. This has the effect
    // of flushing all expired work in a single batch, instead of flushing each
    // level one at a time.
    if(firstScheduledRoot ! = =null) {
      recomputeCurrentRendererTime();/ /! No matter
      let root: FiberRoot = firstScheduledRoot;
      do {
        didExpireAtExpirationTime(root, currentRendererTime);/ /! Flag the variable on the root node to change an attribute to currentTime
        // The root schedule is circular, so this is never null.
        root = (root.nextScheduledRoot: any);
      } while(root ! == firstScheduledRoot);/ /! Traverse the root
    }
  }
  performWork(NoWork, dl);
}

function performSyncWork() {
  performWork(Sync, null);/ /! To sync
}
/ /! The while loop condition has nodes and is in a synchronous/asynchronous state
function performWork(minExpirationTime: ExpirationTime, dl: Deadline | null) {
  deadline = dl;

  // Keep working on roots until there's no more work, or until we reach
  // the deadline.
  findHighestPriorityRoot();/ /! Find the root of the highest priority in root list assigned to nextFlushedRoot and nextFlushedExpirationTimes attributes

  if(deadline ! = =null) {
    recomputeCurrentRendererTime();
    currentSchedulerTime = currentRendererTime;

    if (enableUserTimingAPI) {
      const didExpire = nextFlushedExpirationTime < currentRendererTime;
      const timeout = expirationTimeToMs(nextFlushedExpirationTime);
      stopRequestCallbackTimer(didExpire, timeout);
    }

    while( nextFlushedRoot ! = =null&& nextFlushedExpirationTime ! == NoWork && (minExpirationTime === NoWork ||/ /! MinExpirationTime for sync time will only perform nextFlushedExpirationTime = sync updates and synchronization update minExpirationTime = = = NoWork is asynchronous update All synchronous asynchronous in this or can do itminExpirationTime >= nextFlushedExpirationTime) && (! deadlineDidExpire || currentRendererTime >= nextFlushedExpirationTime)/ /! If the current time is greater than expirationTime, the task is expired
    ) {
      performWorkOnRoot(/ /! Update expiration on root and pass the last value true but not false
        nextFlushedRoot,
        nextFlushedExpirationTime,
        currentRendererTime >= nextFlushedExpirationTime,
      );
      findHighestPriorityRoot();/ /! Find the root high-priority task and execute the next loop
      recomputeCurrentRendererTime();/ /! Recalculate currentTime()currentSchedulerTime = currentRendererTime; }}else {
    while( nextFlushedRoot ! = =null&& nextFlushedExpirationTime ! == NoWork && (minExpirationTime === NoWork ||/ /! MinExpirationTime for sync time will only perform nextFlushedExpirationTime = sync updates and synchronization update minExpirationTime = = = NoWork is asynchronous update All synchronous asynchronous in this or can do it
        minExpirationTime >= nextFlushedExpirationTime)
    ) {
      performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime, true);/ /! Pass true after expirationfindHighestPriorityRoot(); }}// 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 = null;
  }
  // If there's work left over, schedule a new callback.
  if(nextFlushedExpirationTime ! == NoWork) { scheduleCallbackWithExpirationTime( ((nextFlushedRoot: any): FiberRoot), nextFlushedExpirationTime, ); }// Clean-up.
  deadline = null;
  deadlineDidExpire = false;

  finishRendering();
}
Copy the code