行数 https://github.com/a8397550/react-source-share/blob/master/default/react-dom-default.js
function scheduleUpdateOnFiber(fiber, expirationTime) {
// ... 省略
// true
if (expirationTime === Sync) {
if (
// 常量 NoContext = 0
// 初始化时 executionContext = 8 LegacyUnbatchedContext = 8
// 8 & 8 = 8 下条语句初始化时结果为true
(executionContext & LegacyUnbatchedContext) !== NoContext &&
// 初始化 (8 & (16 | 32)) === NoContext 结果为true
(executionContext & (RenderContext | CommitContext)) === NoContext) {
// expirationTime === 1073741823
// 初始化时,啥也没干
schedulePendingInteractions(root, expirationTime);
var callback = renderRoot(root, Sync, true);
while (callback !== null) {
callback = callback(true);
}
} else {
scheduleCallbackForRoot(root, ImmediatePriority, Sync);
if (executionContext === NoContext) {
flushSyncCallbackQueue();
}
}
} else {
scheduleCallbackForRoot(root, priorityLevel, expirationTime);
}
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)) {
// 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 Map([[root, expirationTime]]);
} else {
var lastDiscreteTime = rootsWithPendingDiscreteUpdates.get(root);
if (lastDiscreteTime === undefined || lastDiscreteTime > expirationTime) {
rootsWithPendingDiscreteUpdates.set(root, expirationTime);
}
}
}
}
renderRoot 主要方法
function renderRoot(root, expirationTime, isSync) {
(function () {
// (8 & (16 | 32)) === NoContext 结果为true 取反 false
if (!((executionContext & (RenderContext | CommitContext)) === NoContext)) {
{
throw ReactError(Error('Should not already be working.'));
}
}
})();
// 初始化时 true && 1073741823 !== 1073741823 结果 false
if (enableUserTimingAPI && expirationTime !== Sync) {
var didExpire = isSync;
stopRequestCallbackTimer(didExpire);
}
// 初始化时 1073741823 < 1073741823 结果 false
if (root.firstPendingTime < expirationTime) {
return null;
}
// isSync = true
// root.finishedExpirationTime = 0
// expirationTime = 0
// 初始化时 结果为false
if (isSync && root.finishedExpirationTime === expirationTime) {
return commitRoot.bind(null, root);
}
// 初始化时,默认return了false,啥也没干
flushPassiveEffects();
// root = FiberRootNode
// workInProgressRoot = null
// expirationTime = 1073741823
// renderExpirationTime = 0
if (root !== workInProgressRoot || expirationTime !== renderExpirationTime) {
// prepare 准备 [prɪˈpeə(r)]
// Fresh 新的 [freʃ]
// stack 堆栈 [stæk]
prepareFreshStack(root, expirationTime);
startWorkOnPendingInteractions(root, expirationTime);
} else if (workInProgressRootExitStatus === RootSuspendedWithDelay) {
if (workInProgressRootHasPendingPing) {
prepareFreshStack(root, expirationTime);
} else {
var lastPendingTime = root.lastPendingTime;
if (lastPendingTime < expirationTime) {
return renderRoot.bind(null, root, lastPendingTime);
}
}
}
// workInProgress = FiberNode
if (workInProgress !== null) {
// executionContext = 8
var prevExecutionContext = executionContext;
// 8 | 16 = 24
executionContext |= RenderContext;
// ReactCurrentDispatcher.current = null
var prevDispatcher = ReactCurrentDispatcher.current;
if (prevDispatcher === null) {
/*
var ContextOnlyDispatcher = {
readContext: readContext,
useCallback: throwInvalidHookError,
useContext: throwInvalidHookError,
useEffect: throwInvalidHookError,
useImperativeHandle: throwInvalidHookError,
useLayoutEffect: throwInvalidHookError,
useMemo: throwInvalidHookError,
useReducer: throwInvalidHookError,
useRef: throwInvalidHookError,
useState: throwInvalidHookError,
useDebugValue: throwInvalidHookError,
useResponder: throwInvalidHookError
};
*/
prevDispatcher = ContextOnlyDispatcher;
}
// ReactCurrentDispatcher.current = null 全局变量
ReactCurrentDispatcher.current = ContextOnlyDispatcher;
var prevInteractions = null;
// enableSchedulerTracing = true
if (enableSchedulerTracing) {
// __interactionsRef.current = Set(0)
prevInteractions = __interactionsRef.current;
// root.memoizedInteractions = Set(0)
__interactionsRef.current = root.memoizedInteractions;
}
startWorkLoopTimer(workInProgress);
// 方法形参 isSync = true
if (isSync) {
// expirationTime = 1073741823 !== Sync = 1073741823 结果为false
if (expirationTime !== Sync) {
var currentTime = requestCurrentTime();
if (currentTime < expirationTime) {
executionContext = prevExecutionContext;
resetContextDependencies();
ReactCurrentDispatcher.current = prevDispatcher;
if (enableSchedulerTracing) {
__interactionsRef.current = prevInteractions;
}
return renderRoot.bind(null, root, currentTime);
}
}
} else {
currentEventTime = NoWork;
}
do {
try {
// isSync = true
if (isSync) {
workLoopSync();
} else {
workLoop();
}
break;
} catch (thrownValue) {
resetContextDependencies();
resetHooks();
var sourceFiber = workInProgress;
if (sourceFiber === null || sourceFiber.return === null) {
prepareFreshStack(root, expirationTime);
executionContext = prevExecutionContext;
throw thrownValue;
}
if (enableProfilerTimer && sourceFiber.mode & ProfileMode) {
stopProfilerTimerIfRunningAndRecordDelta(sourceFiber, true);
}
var returnFiber = sourceFiber.return;
throwException(root, returnFiber, sourceFiber, thrownValue, renderExpirationTime);
workInProgress = completeUnitOfWork(sourceFiber);
}
} while (true);
executionContext = prevExecutionContext;
resetContextDependencies();
ReactCurrentDispatcher.current = prevDispatcher;
if (enableSchedulerTracing) {
__interactionsRef.current = prevInteractions;
}
if (workInProgress !== null) {
// There's still work left over. Return a continuation.
stopInterruptedWorkLoopTimer();
if (expirationTime !== Sync) {
startRequestCallbackTimer();
}
return renderRoot.bind(null, root, expirationTime);
}
}
stopFinishedWorkLoopTimer();
root.finishedWork = root.current.alternate;
root.finishedExpirationTime = expirationTime;
var isLocked = resolveLocksOnRoot(root, expirationTime);
if (isLocked) {
return null;
}
workInProgressRoot = null;
switch (workInProgressRootExitStatus) {
case RootIncomplete:
{
(function () {
{
{
throw ReactError(Error('Should have a work-in-progress.'));
}
}
})();
}
case RootErrored:
{
var _lastPendingTime = root.lastPendingTime;
if (_lastPendingTime < expirationTime) {
return renderRoot.bind(null, root, _lastPendingTime);
}
if (!isSync) {
prepareFreshStack(root, expirationTime);
scheduleSyncCallback(renderRoot.bind(null, root, expirationTime));
return null;
}
return commitRoot.bind(null, root);
}
case RootSuspended:
{
flushSuspensePriorityWarningInDEV();
var hasNotProcessedNewUpdates = workInProgressRootLatestProcessedExpirationTime === Sync;
if (hasNotProcessedNewUpdates && !isSync &&
!(true && flushSuspenseFallbacksInTests && IsThisRendererActing.current)) {
var msUntilTimeout = globalMostRecentFallbackTime + FALLBACK_THROTTLE_MS - now();
if (msUntilTimeout > 10) {
if (workInProgressRootHasPendingPing) {
prepareFreshStack(root, expirationTime);
return renderRoot.bind(null, root, expirationTime);
}
var _lastPendingTime2 = root.lastPendingTime;
if (_lastPendingTime2 < expirationTime) {
return renderRoot.bind(null, root, _lastPendingTime2);
}
root.timeoutHandle = scheduleTimeout(commitRoot.bind(null, root), msUntilTimeout);
return null;
}
}
return commitRoot.bind(null, root);
}
case RootSuspendedWithDelay:
{
flushSuspensePriorityWarningInDEV();
if (!isSync &&
!(true && flushSuspenseFallbacksInTests && IsThisRendererActing.current)) {
if (workInProgressRootHasPendingPing) {
prepareFreshStack(root, expirationTime);
return renderRoot.bind(null, root, expirationTime);
}
var _lastPendingTime3 = root.lastPendingTime;
if (_lastPendingTime3 < expirationTime) {
return renderRoot.bind(null, root, _lastPendingTime3);
}
var _msUntilTimeout = void 0;
if (workInProgressRootLatestSuspenseTimeout !== Sync) {
_msUntilTimeout = expirationTimeToMs(workInProgressRootLatestSuspenseTimeout) - now();
} else if (workInProgressRootLatestProcessedExpirationTime === Sync) {
_msUntilTimeout = 0;
} else {
var eventTimeMs = inferTimeFromExpirationTime(workInProgressRootLatestProcessedExpirationTime);
var currentTimeMs = now();
var timeUntilExpirationMs = expirationTimeToMs(expirationTime) - currentTimeMs;
var timeElapsed = currentTimeMs - eventTimeMs;
if (timeElapsed < 0) {
timeElapsed = 0;
}
_msUntilTimeout = jnd(timeElapsed) - timeElapsed;
if (timeUntilExpirationMs < _msUntilTimeout) {
_msUntilTimeout = timeUntilExpirationMs;
}
}
if (_msUntilTimeout > 10) {
root.timeoutHandle = scheduleTimeout(commitRoot.bind(null, root), _msUntilTimeout);
return null;
}
}
return commitRoot.bind(null, root);
}
case RootCompleted:
{
if (!isSync &&
!(true && flushSuspenseFallbacksInTests && IsThisRendererActing.current) && workInProgressRootLatestProcessedExpirationTime !== Sync && workInProgressRootCanSuspendUsingConfig !== null) {
var _msUntilTimeout2 = computeMsUntilSuspenseLoadingDelay(workInProgressRootLatestProcessedExpirationTime, expirationTime, workInProgressRootCanSuspendUsingConfig);
if (_msUntilTimeout2 > 10) {
root.timeoutHandle = scheduleTimeout(commitRoot.bind(null, root), _msUntilTimeout2);
return null;
}
}
return commitRoot.bind(null, root);
}
default:
{
(function () {
{
{
throw ReactError(Error('Unknown root exit status.'));
}
}
})();
}
}
}
flushPassiveEffects
function flushPassiveEffects() {
// 变量rootWithPendingPassiveEffects 默认等于null
if (rootWithPendingPassiveEffects === null) {
return false;
}
var root = rootWithPendingPassiveEffects;
var expirationTime = pendingPassiveEffectsExpirationTime;
var renderPriorityLevel = pendingPassiveEffectsRenderPriority;
rootWithPendingPassiveEffects = null;
pendingPassiveEffectsExpirationTime = NoWork;
pendingPassiveEffectsRenderPriority = NoPriority;
var priorityLevel = renderPriorityLevel > NormalPriority ? NormalPriority : renderPriorityLevel;
return runWithPriority$2(priorityLevel, flushPassiveEffectsImpl.bind(null, root, expirationTime));
}
prepareFreshStack
function prepareFreshStack(root, expirationTime) {
// 初始化时 root.finishedWork = null,root.finishedExpirationTime = 0
// NoWork = 0
root.finishedWork = null;
root.finishedExpirationTime = NoWork;
// root.timeoutHandle 初始化时 = -1
var timeoutHandle = root.timeoutHandle;
// 常量 noTimeout = -1
if (timeoutHandle !== noTimeout) {
root.timeoutHandle = noTimeout;
cancelTimeout(timeoutHandle);
}
// 初始化时 变量 workInProgress = null
if (workInProgress !== null) {
var interruptedWork = workInProgress.return;
while (interruptedWork !== null) {
unwindInterruptedWork(interruptedWork);
interruptedWork = interruptedWork.return;
}
}
// 初始化时 workInProgressRoot = null
// Progress 进程 [ˈprəʊɡres]
workInProgressRoot = root;
workInProgress = createWorkInProgress(root.current, null, expirationTime);
// expirationTime = 1073741823
renderExpirationTime = expirationTime;
// RootIncomplete = 0
workInProgressRootExitStatus = RootIncomplete;
// Sync = 1073741823
workInProgressRootLatestProcessedExpirationTime = Sync;
workInProgressRootLatestSuspenseTimeout = Sync;
workInProgressRootCanSuspendUsingConfig = null;
workInProgressRootHasPendingPing = false;
// enableSchedulerTracing = true
if (enableSchedulerTracing) {
spawnedWorkDuringRender = null;
}
{
/*
ReactStrictModeWarnings = {
discardPendingWarnings: ƒ ()
flushLegacyContextWarning: ƒ ()
flushPendingUnsafeLifecycleWarnings: ƒ ()
recordLegacyContextWarning: ƒ (fiber, instance)
recordUnsafeLifecycleWarnings: ƒ (fiber, instance)
__proto__: Object
}
11858行
ReactStrictModeWarnings.discardPendingWarnings = function () {
pendingComponentWillMountWarnings = [];
pendingUNSAFE_ComponentWillMountWarnings = [];
pendingComponentWillReceivePropsWarnings = [];
pendingUNSAFE_ComponentWillReceivePropsWarnings = [];
pendingComponentWillUpdateWarnings = [];
pendingUNSAFE_ComponentWillUpdateWarnings = [];
pendingLegacyContextWarning = new Map();
};
*/
ReactStrictModeWarnings.discardPendingWarnings();
componentsThatTriggeredHighPriSuspend = null;
}
}
行数 23910 createWorkInProgress [prəˈɡres]
function createWorkInProgress(current, pendingProps, expirationTime) {
// current.alternate 默认为null
var workInProgress = current.alternate;
if (workInProgress === null) {
// current.tag = 3
// pendingProps = null
// current.key = null
// current.mode = 0
workInProgress = createFiber(current.tag, pendingProps,
current.key, current.mode);
// current.elementType = null
workInProgress.elementType = current.elementType;
// current.type = null
workInProgress.type = current.type;
// current.stateNode = FiberRootNode
workInProgress.stateNode = current.stateNode;
{
// DEV-only fields
// current._debugID = 1;
workInProgress._debugID = current._debugID;
// current._debugSource = null;
workInProgress._debugSource = current._debugSource;
// current._debugOwner = null;
workInProgress._debugOwner = current._debugOwner;
// current._debugHookTypes = null;
workInProgress._debugHookTypes = current._debugHookTypes;
}
workInProgress.alternate = current;
current.alternate = workInProgress;
} else {
workInProgress.pendingProps = pendingProps;
workInProgress.effectTag = NoEffect;
workInProgress.nextEffect = null;
workInProgress.firstEffect = null;
workInProgress.lastEffect = null;
if (enableProfilerTimer) {
workInProgress.actualDuration = 0;
workInProgress.actualStartTime = -1;
}
}
// current.childExpirationTime = 0
workInProgress.childExpirationTime = current.childExpirationTime;
// current.expirationTime = 1073741823
workInProgress.expirationTime = current.expirationTime;
// current.child = null
workInProgress.child = current.child;
// current.memoizedProps = null;
workInProgress.memoizedProps = current.memoizedProps;
// current.memoizedState = null;
workInProgress.memoizedState = current.memoizedState;
// 重要 current.updateQueue = {firstUpdate, lastUpdate, ...}
/*
firstUpdate = {
payload: {
element: {$$typeof: Symbol(react.element), ...}
, ...}
, ...}
lastUpdate的结构与firstUpdate一致
*/
workInProgress.updateQueue = current.updateQueue;
// current.dependencies = null
var currentDependencies = current.dependencies;
workInProgress.dependencies = currentDependencies === null ? null : {
expirationTime: currentDependencies.expirationTime,
firstContext: currentDependencies.firstContext,
responders: currentDependencies.responders
};
// current.sibling = null;
workInProgress.sibling = current.sibling;
// current.index = 0;
workInProgress.index = current.index;
// current.ref = null;
workInProgress.ref = current.ref;
// 常量 enableProfilerTimer = true
if (enableProfilerTimer) {
// current.selfBaseDuration = 0;
workInProgress.selfBaseDuration = current.selfBaseDuration;
// current.treeBaseDuration = 0;
workInProgress.treeBaseDuration = current.treeBaseDuration;
}
{
// current._debugNeedsRemount = false;
workInProgress._debugNeedsRemount = current._debugNeedsRemount;
switch (workInProgress.tag) {
case IndeterminateComponent: // 2
case FunctionComponent: // 0
case SimpleMemoComponent: // 15
workInProgress.type = resolveFunctionForHotReloading(current.type);
break;
case ClassComponent: // 1
workInProgress.type = resolveClassForHotReloading(current.type);
break;
case ForwardRef: // 11
workInProgress.type = resolveForwardRefForHotReloading(current.type);
break;
default:
break;
}
}
return workInProgress;
}
startWorkOnPendingInteractions
function startWorkOnPendingInteractions(root, expirationTime) {
// enableSchedulerTracing = true
if (!enableSchedulerTracing) {
return;
}
var interactions = new Set();
// root.pendingInteractionMap.size = 0
root.pendingInteractionMap.forEach(function (scheduledInteractions, scheduledExpirationTime) {
if (scheduledExpirationTime >= expirationTime) {
scheduledInteractions.forEach(function (interaction) {
return interactions.add(interaction);
});
}
});
root.memoizedInteractions = interactions;
if (interactions.size > 0) {
var subscriber = __subscriberRef.current;
if (subscriber !== null) {
var threadID = computeThreadID(root, expirationTime);
try {
subscriber.onWorkStarted(interactions, threadID);
} catch (error) {
// If the subscriber throws, rethrow it in a separate task
scheduleCallback(ImmediatePriority, function () {
throw error;
});
}
}
}
}
startWorkLoopTimer
var formatMarkName = function (markName) {
// reactEmoji = "⚛"
return reactEmoji + ' ' + markName;
};
var beginMark = function (markName) {
// performance 需要注意这个玩意是window.performance
// performance 主要用来做性能监控,白屏时间,首屏时间,用户可操作时间节点,总下载时间...
performance.mark(formatMarkName(markName));
};
var resumeTimers = function () {
// currentFiber = FiberNode # renderRoot 传入 workInProgress
if (currentFiber !== null) {
resumeTimersRecursively(currentFiber);
}
};
var resumeTimersRecursively = function (fiber) {
// fiber.return = null
if (fiber.return !== null) {
resumeTimersRecursively(fiber.return);
}
// fiber._debugIsCurrentlyTiming = false
if (fiber._debugIsCurrentlyTiming) {
beginFiberMark(fiber, null);
}
};
function startWorkLoopTimer(nextUnitOfWork) {
// enableUserTimingAPI = true
if (enableUserTimingAPI) {
// nextUnitOfWork = FiberNode # renderRoot 传入 workInProgress
currentFiber = nextUnitOfWork;
// supportsUserTiming = true
if (!supportsUserTiming) {
return;
}
commitCountInCurrentWorkLoop = 0;
beginMark('(React Tree Reconciliation)');
// Resume any measurements that were in progress during the last loop.
resumeTimers();
}
}
行数 22320 workLoopSync
function workLoopSync() {
// workInProgress = FiberNode
while (workInProgress !== null) {
workInProgress = performUnitOfWork(workInProgress);
}
}
function performUnitOfWork(unitOfWork) {
// The current, flushed, state of this fiber is the alternate. Ideally
// nothing should rely on this, but relying on it here means that we don't
// need an additional field on the work in progress.
var current$$1 = unitOfWork.alternate;
startWorkTimer(unitOfWork);
setCurrentFiber(unitOfWork);
var next = void 0;
if (enableProfilerTimer && (unitOfWork.mode & ProfileMode) !== NoMode) {
startProfilerTimer(unitOfWork);
next = beginWork$$1(current$$1, unitOfWork, renderExpirationTime);
stopProfilerTimerIfRunningAndRecordDelta(unitOfWork, true);
} else {
next = beginWork$$1(current$$1, unitOfWork, renderExpirationTime);
}
resetCurrentFiber();
unitOfWork.memoizedProps = unitOfWork.pendingProps;
if (next === null) {
// If this doesn't spawn new work, complete the current work.
next = completeUnitOfWork(unitOfWork);
}
ReactCurrentOwner$2.current = null;
return next;
}