Skip to content
目录

全局变量参考

  • isHostCallbackScheduled

是否已经开始调度了,在ensureHostCallbackIsScheduled设置为true,在结束执行callback之后设置为false

  • scheduledHostCallback

在requestHostCallback设置,值一般为flushWork,代表下一个调度要做的事情

  • isMessageEventScheduled

是否已经发送调用idleTick的消息,在animationTick中设置为true

  • timeoutTime

表示过期任务的时间,在idleTick中发现第一个任务的时间已经过期的时候设置

  • isAnimationFrameScheduled

是否已经开始调用requestAnimationFrame

  • activeFrameTime

给一帧渲染用的时间,默认是 33,也就是 1 秒 30 帧

  • frameDeadline

记录当前帧的到期时间,他等于currentTime + activeFraeTime,也就是requestAnimationFrame回调传入的时间,加上一帧的时间。

  • isFlushingHostCallback

是否正在执行callback

注意

react模拟实现requestIdeaCallback的调用,发生在requestWork阶段,当前更新为异步的时候,调用scheduleCallbackWithExpirationTime;

默认模式下,在当前16版本是不会进入到scheduleCallbackWithExpirationTime方法的,需要开启ConcurrentMode

scheduleCallbackWithExpirationTime

typescript
function scheduleCallbackWithExpirationTime(
  root: FiberRoot,
  expirationTime: ExpirationTime,
) {
  if (callbackExpirationTime !== NoWork) {
    // 如果callbackExpirationTime不等于NoWork
    // 说明当前已经有更新任务在执行
    if (expirationTime < callbackExpirationTime) {
      // 如果当前任务的expirationTime 小于上一个正在执行的任务的expirationTime
      // 说明当前需要调度的任务的优先级较低 较低的话 等待任务的调度就好了
      return;
    } else {
      // 否则 说明优先级较高 , 将上一个优先级较低的任务调度取消掉
      if (callbackID !== null) {
        cancelDeferredCallback(callbackID);
      }
    }
  } else {
    startRequestCallbackTimer();
  }
  // 记录当前任务的exiprationTime
  callbackExpirationTime = expirationTime;
  // 获取当前距离js文件距离一开始被加载的毫秒数
  const currentMs = now() - originalStartTimeMs;
  // 将expitationTime转化成毫秒 expirationTime 也是根据originalStartTimeMs 来计算的
  const expirationTimeMs = expirationTimeToMs(expirationTime);
  // 计算当前任务的超时时间 毫秒 
  const timeout = expirationTimeMs - currentMs;
  // 将performAsyncWork传入 开始调度
  callbackID = scheduleDeferredCallback(performAsyncWork, {timeout});
}

unstable_scheduleCallback

scheduleDeferredCallback最终调用的其实是unstable_scheduleCallback;这个函数在react-schedule包里面

typescript
function unstable_scheduleCallback(callback, deprecated_options) {
  // 获取当前的时间戳
  var startTime =
    currentEventStartTime !== -1 ? currentEventStartTime : getCurrentTime();

  var expirationTime;
  if (
    typeof deprecated_options === 'object' &&
    deprecated_options !== null &&
    typeof deprecated_options.timeout === 'number'
  ) {
    // 计算出超时时间戳
    // FIXME: Remove this branch once we lift expiration times out of React.
    expirationTime = startTime + deprecated_options.timeout;
  } else {
    // 如果没有传timeout 会走这个逻辑
    // 目前这里是用不到的 应该是React为了以后的版本做的铺垫
    switch (currentPriorityLevel) {
      case ImmediatePriority:
        expirationTime = startTime + IMMEDIATE_PRIORITY_TIMEOUT;
        break;
      case UserBlockingPriority:
        expirationTime = startTime + USER_BLOCKING_PRIORITY;
        break;
      case IdlePriority:
        expirationTime = startTime + IDLE_PRIORITY;
        break;
      case LowPriority:
        expirationTime = startTime + LOW_PRIORITY_TIMEOUT;
        break;
      case NormalPriority:
      default:
        expirationTime = startTime + NORMAL_PRIORITY_TIMEOUT;
    }
  }

  // 创建一个调度的节点
  // 存着callback 以及 expirationTime
  var newNode = {
    callback,
    priorityLevel: currentPriorityLevel,
    expirationTime,
    next: null,
    previous: null,
  };
  // 首先判断当前调度链表的头节点
  if (firstCallbackNode === null) {
    // 如果头结点是空 说明这个newNode是第一个节点
    // 将firstCallbackNode赋值 并形成一个环状链表
    firstCallbackNode = newNode.next = newNode.previous = newNode;
    ensureHostCallbackIsScheduled();
  } else {
    var next = null;
    var node = firstCallbackNode;
    // 遍历当前链表 找到第一个过期时间比当前newNode大的节点
    // 如果能找到 就把newNode查在当前next的前面
    do {
      if (node.expirationTime > expirationTime) {
        next = node;
        break;
      }
      node = node.next;
    } while (node !== firstCallbackNode);

    if (next === null) {
      // 如果找不到 说明当前newNode在链表中是expirationTime最大的
      // 即优先级最低的 此时要将newNode插在链表最后
      next = firstCallbackNode;
    } else if (next === firstCallbackNode) {
      // 如果第一个节点就比当前newNode的expirationTime大也就是将newNode
      // 插入到链表的第一个
      // 说明当前newNode节点是优先级最高的
      // 将firstCallbackNode指向当前newNode、
      firstCallbackNode = newNode;
      ensureHostCallbackIsScheduled();
    }
    // 执行链表的插入
    var previous = next.previous;
    previous.next = next.previous = newNode;
    newNode.next = next;
    newNode.previous = previous;
  }
  return newNode;
}

firstCallbackNode就是循环链表的头结点,将需要调度的任务用链表串联起来

ensureHostCallbackIsScheduled

typescript
function ensureHostCallbackIsScheduled() {
  // 这是在执行回调时设置的,以防止再次进入。 默认为false
  if (isExecutingCallback) {
    return;
  }
  var expirationTime = firstCallbackNode.expirationTime;
  if (!isHostCallbackScheduled) {
    isHostCallbackScheduled = true;
  } else {
    // Cancel the existing host callback.
    cancelHostCallback();
  }
  // 调度的关键
  requestHostCallback(flushWork, expirationTime);
}

requestHostCallback

typescript
requestHostCallback = function(callback, absoluteTimeout) {
    // scheduledHostCallback 就是 flushWork
    scheduledHostCallback = callback;
    timeoutTime = absoluteTimeout;
    if (isFlushingHostCallback || absoluteTimeout < 0) {
      // 如果符合这个条件 不需要等待 requestAnimationFrame 的下一帧去调度
      // 而是立马去调度
      // Don't wait for the next frame. Continue working ASAP, in a new event.
      port.postMessage(undefined);
    } else if (!isAnimationFrameScheduled) {
      // requestAnimationFrame没有在执行,则开始一帧的执行
      isAnimationFrameScheduled = true;
      requestAnimationFrameWithTimeout(animationTick);
    }
  };

requestAnimationFrameWithTimeout

typescript
var requestAnimationFrameWithTimeout = function(callback) {
  // schedule rAF and also a setTimeout
  rAFID = localRequestAnimationFrame(function(timestamp) {
    // cancel the setTimeout
    localClearTimeout(rAFTimeoutID);
    // 这里的callback就是animationTick,
    // 当前的timestamp就是requestAnimationFrame的参数
    // 它表示requestAnimationFrame() 开始去执行回调函数的时刻。
    callback(timestamp);
  });
  // timeout的作用是防止requestAnimationFrame没有被调用
  // 在100ms内必须调用
  rAFTimeoutID = localSetTimeout(function() {
    // cancel the requestAnimationFrame
    localCancelAnimationFrame(rAFID);
    callback(getCurrentTime());
  }, ANIMATION_FRAME_TIMEOUT);
};

animationTick

animationTick也就是requestAnimationFrame的回调,接受一个参数,为开始调用animationTick时候的时间戳

typescript
var animationTick = function(rafTime) {
    if (scheduledHostCallback !== null) {
      requestAnimationFrameWithTimeout(animationTick);
    } else {
      // No pending work. Exit.
      isAnimationFrameScheduled = false;
      return;
    }
    // 计算一贞的时间
    // 第一次就是当前时间戳 加上 33
    // 但是第二次执行到animationTick的时候
    // nextFrameTime = rafTime - ( rafTime(这个是上一次的rafTime) + activeFrameTime ) + activeFrameTime;
    // 也就是 nextFrameTime = refTime - refTime(上一次的)
    // 连续两次对animationTick的调用的时间差 即当前系统的一贞刷新的时间
    var nextFrameTime = rafTime - frameDeadline + activeFrameTime;
    if (
      nextFrameTime < activeFrameTime &&
      previousFrameTime < activeFrameTime
    ) {
      // react不支持120HZ以上的贞
      // 如果当前大于120HZ也就是贞时间小于8
      // 那么就将贞数等于8
      if (nextFrameTime < 8) {
        nextFrameTime = 8;
      }
      // 更新activeFrameTime
      activeFrameTime =
        nextFrameTime < previousFrameTime ? previousFrameTime : nextFrameTime;
    } else {
      previousFrameTime = nextFrameTime;
    }
    // 当前帧到期的时间戳
    frameDeadline = rafTime + activeFrameTime;
    if (!isMessageEventScheduled) {
      isMessageEventScheduled = true;
      port.postMessage(undefined);
    }
  };

MessageChannel

如果在animationTick发送完消息后,当MessageChannel接受消息执行的时候,说明此时为空闲;也就是浏览器的在一贞要做的事情坐完了,说明轮到react来执行了

typescript
channel.port1.onmessage = function(event) {
    isMessageEventScheduled = false;
    var prevScheduledCallback = scheduledHostCallback;
    var prevTimeoutTime = timeoutTime;
    scheduledHostCallback = null;
    timeoutTime = -1;
    var currentTime = getCurrentTime();
    var didTimeout = false;
    // 如果frameDeadline小于当前时间 说明当前帧的时间到了
    if (frameDeadline - currentTime <= 0) {
      // 当当前帧的时间到了后,判断timeoutTime跟当前的时间大小
      // 如果prevTimeoutTime <= currentTime 说明当前任务过期了
      if (prevTimeoutTime !== -1 && prevTimeoutTime <= currentTime) {
        didTimeout = true;
      } else {
        // 否则 没有超时 可以放到下一帧执行
        if (!isAnimationFrameScheduled) {
          // Schedule another animation callback so we retry later.
          isAnimationFrameScheduled = true;
          requestAnimationFrameWithTimeout(animationTick);
        }
        // Exit without invoking the callback.
        scheduledHostCallback = prevScheduledCallback;
        timeoutTime = prevTimeoutTime;
        return;
      }
    }

    if (prevScheduledCallback !== null) {
      isFlushingHostCallback = true;
      try {
        // 直接执行
        // 这里的 prevScheduledCallback 就是 scheduledHostCallback
        // 也就是 flushWork
        prevScheduledCallback(didTimeout);
      } finally {
        isFlushingHostCallback = false;
      }
    }
  };

flushWork

typescript
function flushWork(didTimeout) {
  isExecutingCallback = true;
  const previousDidTimeout = currentDidTimeout;
  currentDidTimeout = didTimeout;
  try {
    if (didTimeout) {
      // 如果超时了
      while (
        firstCallbackNode !== null &&
        !(enableSchedulerDebugging && isSchedulerPaused)
      ) {
        var currentTime = getCurrentTime();
        // firstCallbackNode.expirationTime 如果小于当前时间
        // 说明当前的node是一个超时的
        if (firstCallbackNode.expirationTime <= currentTime) {
          do {
            // 将超时的节点执行掉
            // firstCallbackNode 指针更新到下一个node
            flushFirstCallback();
          } while (
            firstCallbackNode !== null &&
            firstCallbackNode.expirationTime <= currentTime &&
            !(enableSchedulerDebugging && isSchedulerPaused)
          );
          continue;
        }
        break;
      }
    } else {
      // 没有超时的话
      if (firstCallbackNode !== null) {
        do {
          if (enableSchedulerDebugging && isSchedulerPaused) {
            break;
          }
          flushFirstCallback();
          // 继续执行回调 直到一贞的时间用完
        } while (firstCallbackNode !== null && !shouldYieldToHost());
      }
    }
  } finally {
    isExecutingCallback = false;
    currentDidTimeout = previousDidTimeout;
    if (firstCallbackNode !== null) {
      ensureHostCallbackIsScheduled();
    } else {
      isHostCallbackScheduled = false;
    }
  }
}

flushFirstCallback

typescript
function flushFirstCallback() {
  // 从链表中取出要执行的node
  var flushedNode = firstCallbackNode;
  var next = firstCallbackNode.next;
  if (firstCallbackNode === next) {
    // This is the last callback in the list.
    firstCallbackNode = null;
    next = null;
  } else {
    var lastCallbackNode = firstCallbackNode.previous;
    firstCallbackNode = lastCallbackNode.next = next;
    next.previous = lastCallbackNode;
  }

  flushedNode.next = flushedNode.previous = null;

  var callback = flushedNode.callback;
  var expirationTime = flushedNode.expirationTime;
  var priorityLevel = flushedNode.priorityLevel;
  var previousPriorityLevel = currentPriorityLevel;
  var previousExpirationTime = currentExpirationTime;
  currentPriorityLevel = priorityLevel;
  currentExpirationTime = expirationTime;
  var continuationCallback;
  try {
    // 直接执行 这里的callback就是一开始存在newNode上的callback
    // 也就是 performAsyncWork
    continuationCallback = callback();
  } finally {
    currentPriorityLevel = previousPriorityLevel;
    currentExpirationTime = previousExpirationTime;
  }
}

备案号: 浙ICP备2023000081号