全局变量参考
- 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
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包里面
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
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
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
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时候的时间戳
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来执行了
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
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
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;
}
}