行数
https://github.com/a8397550/react-source-share/blob/master/default/react-dom-default.js
JavaScript 位运算符
位运算符工作于32位的数字上。任何数字操作都将转换为32位。结果会转换为 JavaScript 数字。
| 运算符 | 描述 | 例子 | 类似于 | 结果 | 十进制 |
|---|---|---|---|---|---|
| & | AND | x = 5 & 1 | 0101 & 0001 | 0001 | 1 |
| | | OR | x = 5 | 1 | 0101 | 0001 | 0101 | 5 |
| ~ | 取反 | x = ~ 5 | ~0101 | 1010 | -6 |
| ^ | 异或 | x = 5 ^ 1 | 0101 ^ 0001 | 0100 | 4 |
| << | 左移 | x = 5 << 1 | 0101 << 1 | 1010 | 10 |
| >> | 右移 | x = 5 >> 1 | 0101 >> 1 | 0010 | 2 |
// 默认的时候 undefinedvar root = container._reactRootContainer;// fiber [faɪbə] 构造的意思var fiberRoot = void 0;if (!root) {root = container._reactRootContainer =legacyCreateRootFromDOMContainer(container, forceHydrate);fiberRoot = root._internalRoot; // 将创建好的FiberRootNode赋值给fiberRootif (typeof callback === 'function') {var originalCallback = callback;callback = function () {var instance = getPublicRootInstance(fiberRoot);originalCallback.call(instance);};}unbatchedUpdates(function () {// children ReactElements// fiberRoot FiberRootNode// parentComponent undefined// callback undefinedupdateContainer(children, fiberRoot, parentComponent, callback);});} else {// ...}
行数:21820
此处注意 finally 中的 flushSyncCallbackQueue
function unbatchedUpdates(fn, a) {// executionContext 初始值是0// prevExecutionContext = 0var prevExecutionContext = executionContext;// 位运算// 初始化时 executionContext = 0 & ~1 = 0executionContext = executionContext & ~BatchedContext;// 初始化时 executionContext = 0 | 8 = 8executionContext = executionContext | LegacyUnbatchedContext;try {// 初始化时 a = undefinedreturn fn(a);} finally {// 恢复executionContext的值// 初始化时,executionContext = prevExecutionContext = 0executionContext = prevExecutionContext;// NoContext 初始值是 0if (executionContext === NoContext) {flushSyncCallbackQueue();}}}function updateContainer(element, container, parentComponent, callback) {// FiberRootNode.current FiberNode// 取出定义好的当前的FiberNode// container 等于 FiberRootNodevar current$$1 = container.current;// 例子 1073711812var currentTime = requestCurrentTime();{// jest没有赋值的地方,应该是作者打的一个与debug有关的标志if ('undefined' !== typeof jest) {warnIfUnmockedScheduler(current$$1);warnIfNotScopedWithMatchingAct(current$$1);}}// 初始化时 requestCurrentSuspenseConfig() return 了 null// suspenseConfig = null;var suspenseConfig = requestCurrentSuspenseConfig();// 初始化时 expirationTime = 1073741823var expirationTime = computeExpirationForFiber(currentTime, current$$1, suspenseConfig);// 初始化时,入参如下// element = ReactElements// container = DOMElement// parentComponent = null// expirationTime = 常量 1073741823// suspenseConfig = null// callback = undefinedreturn updateContainerAtExpirationTime(element, container,parentComponent, expirationTime, suspenseConfig, callback);}var ReactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;var ReactCurrentBatchConfig = ReactSharedInternals.ReactCurrentBatchConfig;function requestCurrentSuspenseConfig() {// 初始化时 ReactCurrentBatchConfig.suspense 值 为nullreturn ReactCurrentBatchConfig.suspense;}function requestCurrentTime() {// 初始化时,(8 & (16 | 32)) !== 0 结果 falseif ((executionContext & (RenderContext | CommitContext)) !== NoContext) {return msToExpirationTime(now());}// 初始化时 0 !== 0 返回 falseif (currentEventTime !== NoWork) {return currentEventTime;}currentEventTime = msToExpirationTime(now());// 例子 currentEventTime = 1073711812return currentEventTime;}/*** 1个到期时间单位表示10毫秒。*/function msToExpirationTime(ms) {// 例子 ms = 300098.8250000082// 总是加一个偏移量,这样我们就不会和现在的数字冲突。// 默认值 MAGIC_NUMBER_OFFSET =// (Batched = (Sync = MAX_SIGNED_31_BIT_INT = 1073741823) - 1) - 1// MAGIC_NUMBER_OFFSET = 1073741821// UNIT_SIZE = 10return MAGIC_NUMBER_OFFSET - (ms / UNIT_SIZE | 0);}var ReactInternals$1 = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;var _ReactInternals$Sched = ReactInternals$1.Scheduler;var unstable_now = _ReactInternals$Sched.unstable_now;var Scheduler_now = unstable_now;var now = initialTimeMs < 10000 ? Scheduler_now : function () {// Scheduler_now 代码在React.js 2276行return Scheduler_now() - initialTimeMs;};// 以下这段代码在React.js中var getCurrentTime = void 0;getCurrentTime = function () {return Date.now();}getCurrentTime = typeof performance === 'object' && typeof performance.now === 'function' ? function () {return performance.now();} : function () {return _Date.now();};
// 初始化调用时// currentTime = 1073740102// fiber = FiberNode// suspenseConfig = nullfunction computeExpirationForFiber(currentTime, fiber, suspenseConfig) {// 初始化时 fiber.mode = 0var mode = fiber.mode;// 0 & 2 === 0 结果trueif ((mode & BatchedMode) === NoMode) {// 返回常量值 1073741823return Sync;}var priorityLevel = getCurrentPriorityLevel();if ((mode & ConcurrentMode) === NoMode) {return priorityLevel === ImmediatePriority ? Sync : Batched;}if ((executionContext & RenderContext) !== NoContext) {// Use whatever time we're already renderingreturn renderExpirationTime;}var expirationTime = void 0;if (suspenseConfig !== null) {// Compute an expiration time based on the Suspense timeout.expirationTime = computeSuspenseExpiration(currentTime, suspenseConfig.timeoutMs | 0 || LOW_PRIORITY_EXPIRATION);} else {// Compute an expiration time based on the Scheduler priority.switch (priorityLevel) {case ImmediatePriority:expirationTime = Sync;break;case UserBlockingPriority$2:// TODO: Rename this to computeUserBlockingExpirationexpirationTime = computeInteractiveExpiration(currentTime);break;case NormalPriority:case LowPriority:// TODO: Handle LowPriority// TODO: Rename this to... something better.expirationTime = computeAsyncExpiration(currentTime);break;case IdlePriority:expirationTime = Never;break;default:(function () {{{throw ReactError(Error('Expected a valid priority level'));}}})();}}if (workInProgressRoot !== null && expirationTime === renderExpirationTime) {// This is a trick to move this update into a separate batchexpirationTime -= 1;}return expirationTime;}
行数 24462 updateContainerAtExpirationTime(element, container, parentComponent, expirationTime, suspenseConfig, callback)
核心代码 scheduleRootUpdate 工作计划 [ˈskedʒuːl]
var ReactFiberInstrumentation = {debugTool: null};var ReactFiberInstrumentation_1 = ReactFiberInstrumentation;function updateContainerAtExpirationTime(element, container, parentComponent, expirationTime, suspenseConfig, callback) {// FiberNodovar current$$1 = container.current;{// 初始化时 ReactFiberInstrumentation_1.debugTool = nullif (ReactFiberInstrumentation_1.debugTool) {if (current$$1.alternate === null) {ReactFiberInstrumentation_1.debugTool.onMountContainer(container);} else if (element === null) {ReactFiberInstrumentation_1.debugTool.onUnmountContainer(container);} else {ReactFiberInstrumentation_1.debugTool.onUpdateContainer(container);}}}// 初始化时 parentComponent值 为null// context = {}var context = getContextForSubtree(parentComponent);// 初始化时 container.context = nullif (container.context === null) {container.context = context;} else {container.pendingContext = context;}// 初始化时,入参如下// current$$1 = FiberNode// element = ReactElements// expirationTime = 常量 1073741823// suspenseConfig = null// callback = undefinedreturn scheduleRootUpdate(current$$1, element, expirationTime, suspenseConfig, callback);}var emptyContextObject = {};{Object.freeze(emptyContextObject);}// 初始化时,入参为nullfunction getContextForSubtree(parentComponent) {if (!parentComponent) {return emptyContextObject;}var fiber = get(parentComponent);var parentContext = findCurrentUnmaskedContext(fiber);if (fiber.tag === ClassComponent) {var Component = fiber.type;if (isContextProvider(Component)) {return processChildContext(fiber, Component, parentContext);}}return parentContext;}
核心 24434 scheduleRootUpdate(current$$1, element, expirationTime, suspenseConfig, callback)
21526行 负责执行scheduleWork
function scheduleRootUpdate(current$$1, element, expirationTime, suspenseConfig, callback) {{if (phase === 'render' && current !== null && !didWarnAboutNestedUpdates) {didWarnAboutNestedUpdates = true;warningWithoutStack$1(false, 'Render methods should be a pure function of props and state; ' + 'triggering nested component updates from Render is not allowed. ' + 'If necessary, trigger nested updates in componentDidUpdate.\n\n' + 'Check the Render method of %s.', getComponentName(current.type) || 'Unknown');}}var update = createUpdate(expirationTime, suspenseConfig);update.payload = { element: element };callback = callback === undefined ? null : callback;if (callback !== null) {!(typeof callback === 'function') ? warningWithoutStack$1(false, 'Render(...): Expected the last optional `callback` argument to be a ' + 'function. Instead received: %s.', callback) : void 0;update.callback = callback;}// revertPassiveEffectsChange 默认值 falseif (revertPassiveEffectsChange) {flushPassiveEffects();}// enenqueue 排队,FiberNode// 给FiberNode加上updateQueue属性enqueueUpdate(current$$1, update);// schedule [ˈskedʒuːl] 工作计划// var scheduleWork = scheduleUpdateOnFiber;scheduleWork(current$$1, expirationTime);return expirationTime;}// expirationTime = 1073741823// suspenseConfig = nullfunction createUpdate(expirationTime, suspenseConfig) {var update = {expirationTime: expirationTime,suspenseConfig: suspenseConfig,// UpdateState 常量值 0tag: UpdateState,payload: null,callback: null,next: null,nextEffect: null};{update.priority = getCurrentPriorityLevel();}return update;}function getCurrentPriorityLevel() {switch (Scheduler_getCurrentPriorityLevel()) {// Scheduler_ImmediatePriority = 1case Scheduler_ImmediatePriority:// ImmediatePriority = 99return ImmediatePriority;// Scheduler_UserBlockingPriority = 2case Scheduler_UserBlockingPriority:// UserBlockingPriority$2 = 98return UserBlockingPriority$2;// Scheduler_NormalPriority = 3case Scheduler_NormalPriority:// NormalPriority = 97return NormalPriority;// Scheduler_LowPriority = 4case Scheduler_LowPriority:// LowPriority = 96return LowPriority;// Scheduler_IdlePriority = 5case Scheduler_IdlePriority:// IdlePriority = 95return IdlePriority;default:(function () {{{throw ReactError(Error('Unknown priority level.'));}}})();}}// 此代码出处React.jsfunction unstable_getCurrentPriorityLevel () {// currentPriorityLevel 默认值是3 是一个变量return currentPriorityLevel;}
function enqueueUpdate(fiber, update) {
// 更新队列是惰性创建的
// fiber.alternate 默认为 null
var alternate = fiber.alternate;
var queue1 = void 0;
var queue2 = void 0;
if (alternate === null) {
// fiber.updateQueue 默认为 null
queue1 = fiber.updateQueue;
queue2 = null;
if (queue1 === null) {
// fiber.memoizedState 默认值为 null
queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState);
}
} else {
// There are two owners.
queue1 = fiber.updateQueue;
queue2 = alternate.updateQueue;
if (queue1 === null) {
if (queue2 === null) {
// Neither fiber has an update queue. Create new ones.
queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState);
queue2 = alternate.updateQueue = createUpdateQueue(alternate.memoizedState);
} else {
// Only one fiber has an update queue. Clone to create a new one.
queue1 = fiber.updateQueue = cloneUpdateQueue(queue2);
}
} else {
if (queue2 === null) {
// Only one fiber has an update queue. Clone to create a new one.
queue2 = alternate.updateQueue = cloneUpdateQueue(queue1);
} else {
// Both owners have an update queue.
}
}
}
// 初始化时 queue2 = null || queue1 = {...}
if (queue2 === null || queue1 === queue2) {
appendUpdateToQueue(queue1, update);
} else {
// There are two queues. We need to append the update to both queues,
// while accounting for the persistent structure of the list — we don't
// want the same update to be added multiple times.
if (queue1.lastUpdate === null || queue2.lastUpdate === null) {
// One of the queues is not empty. We must add the update to both queues.
appendUpdateToQueue(queue1, update);
appendUpdateToQueue(queue2, update);
} else {
// Both queues are non-empty. The last update is the same in both lists,
// because of structural sharing. So, only append to one of the lists.
appendUpdateToQueue(queue1, update);
// But we still need to update the `lastUpdate` pointer of queue2.
queue2.lastUpdate = update;
}
}
{
// fiber.tag = 3
// ClassComponent = 1
// currentlyProcessingQueue 默认值为 null
// didWarnUpdateInsideUpdate = false
// queue2 = null
if (fiber.tag === ClassComponent && (currentlyProcessingQueue === queue1 ||
queue2 !== null && currentlyProcessingQueue === queue2) &&
!didWarnUpdateInsideUpdate) {
warningWithoutStack$1(false, 'An update (setState, replaceState, or forceUpdate) was scheduled ' + 'from inside an update function. Update functions should be pure, ' + 'with zero side-effects. Consider using componentDidUpdate or a ' + 'callback.');
didWarnUpdateInsideUpdate = true;
}
}
}
function createUpdateQueue(baseState) {
var queue = {
baseState: baseState,
firstUpdate: null,
lastUpdate: null,
firstCapturedUpdate: null,
lastCapturedUpdate: null,
firstEffect: null,
lastEffect: null,
firstCapturedEffect: null,
lastCapturedEffect: null
};
return queue;
}
function appendUpdateToQueue(queue, update) {
// 初始化时 queue.lastUpdate = null
if (queue.lastUpdate === null) {
// Queue is empty
queue.firstUpdate = queue.lastUpdate = update;
} else {
queue.lastUpdate.next = update;
queue.lastUpdate = update;
}
}
