# PendingPriority

# earliestPendingTime

# latestPendingTime

# CommittedPriority

# earliestPendingTime

# latestPendingTime

# SuspendedPriority

# earliestSuspendedTime

# latestSuspendedTime

# PingedPriority

# latestPingedTime

# currentRendererTime
function recomputeCurrentRendererTime() {
  const currentTimeMs = now() - originalStartTimeMs;
  currentRendererTime = msToExpirationTime(currentTimeMs);
}

const UNIT_SIZE = 10;
const MAGIC_NUMBER_OFFSET = 2;
export function msToExpirationTime(ms: number): ExpirationTime {
  // Always add an offset so that we don't clash with the magic number for NoWork.
  return ((ms / UNIT_SIZE) | 0) + MAGIC_NUMBER_OFFSET;
}
# callbackExpirationTime

用来记录上次异步调度的超时时间,在scheduleCallbackWithExpirationTime中设置成expirationTime,在回调performWork开始时设置成NoWork,这是为了防止连续出现两次回调,

callbackExpirationTime中的判断,如果第二次调用的expirationTime比第一次的超时时间小,则要撤销上一次回调,使用这次的expirationTime进行回调

if (callbackExpirationTime !== NoWork) {
  // A callback is already scheduled. Check its expiration time (timeout).
  if (expirationTime > callbackExpirationTime) {
    // Existing callback has sufficient timeout. Exit.
    return;
  } else {
    if (callbackID !== null) {
      // Existing callback has insufficient timeout. Cancel and schedule a
      // new one.
      cancelDeferredCallback(callbackID);
    }
  }
  // The request callback timer is already running. Don't start a new one.
} else {
  startRequestCallbackTimer();
}
# nextLatestAbsoluteTimeoutMs

这个时间是一旦遇到placeholder并且设置了delayMs,在这个时间结束之前,会设置到nextLatestAbsoluteTimeoutMs

resetStack的时候被设置为-1

renderRoot的时候

if (enableSuspense && !isExpired && nextLatestAbsoluteTimeoutMs !== -1) {
  // The tree was suspended.
  const suspendedExpirationTime = expirationTime;
  markSuspendedPriorityLevel(root, suspendedExpirationTime);

  const earliestExpirationTime = findEarliestOutstandingPriorityLevel(
    root,
    expirationTime,
  );
  const earliestExpirationTimeMs = expirationTimeToMs(earliestExpirationTime);
  if (earliestExpirationTimeMs < nextLatestAbsoluteTimeoutMs) {
    nextLatestAbsoluteTimeoutMs = earliestExpirationTimeMs;
  }

  // 。。。。。。
}

renderDidSuspend的时候,这个方法在throwException里面调用,也就是只有真的抛出一个promise的时候才会调用

可以认为一旦能执行到renderDidSuspend说明nextLatestAbsoluteTimeoutMs肯定是大于0的,并且placeholder还没有过期(不确定过期在哪里设置,也不确定是否超过了delayMs就是过期)

function renderDidSuspend(
  root: FiberRoot,
  absoluteTimeoutMs: number,
  suspendedTime: ExpirationTime,
) {
  // Schedule the timeout.
  if (
    absoluteTimeoutMs >= 0 &&
    nextLatestAbsoluteTimeoutMs < absoluteTimeoutMs
  ) {
    nextLatestAbsoluteTimeoutMs = absoluteTimeoutMs;
  }
}

// 关键代码
const didTimeout = workInProgress.memoizedState;
if (!didTimeout) {
  if ((workInProgress.mode & StrictMode) === NoEffect) {
    // ...
    return
  }
  
  let absoluteTimeoutMs;
  if (earliestTimeoutMs === -1) {
    absoluteTimeoutMs = maxSigned31BitInt;
  } else {
    if (startTimeMs === -1) {
      const earliestExpirationTime = findEarliestOutstandingPriorityLevel(
        root,
        renderExpirationTime,
      );
      const earliestExpirationTimeMs = expirationTimeToMs(
        earliestExpirationTime,
      );
      startTimeMs = earliestExpirationTimeMs - LOW_PRIORITY_EXPIRATION;
    }
    absoluteTimeoutMs = startTimeMs + earliestTimeoutMs;
  }

  renderDidSuspend(root, absoluteTimeoutMs, renderExpirationTime);
  // ...
}

计算earliestTimeoutMs,可以认为是在PlaceholderComponent还没过期的时候的delayMs这个props的值,并且是向上找到最小的delayMs

let earliestTimeoutMs = -1;
let startTimeMs = -1;
do {
  if (workInProgress.tag === PlaceholderComponent) {
    const current = workInProgress.alternate;
    if (
      current !== null &&
      current.memoizedState === true &&
      current.stateNode !== null
    ) {
      // Reached a placeholder that already timed out. Each timed out
      // placeholder acts as the root of a new suspense boundary.

      // Use the time at which the placeholder timed out as the start time
      // for the current render.
      const timedOutAt = current.stateNode.timedOutAt;
      startTimeMs = expirationTimeToMs(timedOutAt);

      // Do not search any further.
      break;
    }
    let timeoutPropMs = workInProgress.pendingProps.delayMs;
    if (typeof timeoutPropMs === 'number') {
      if (timeoutPropMs <= 0) {
        earliestTimeoutMs = 0;
      } else if (
        earliestTimeoutMs === -1 ||
        timeoutPropMs < earliestTimeoutMs
      ) {
        earliestTimeoutMs = timeoutPropMs;
      }
    }
  }

startTimeMs则是记录已经过期的placeholdertimedOutAt属性current.memoizedState === true代表已经过期。一旦找到一个过期的则直接break

const timedOutAt = current.stateNode.timedOutAt;
startTimeMs = expirationTimeToMs(timedOutAt);
# nextRenderDidError

在抛出错误并且不是Promise的时候会设置成ture,代表真的有错误