Source: scheduleUpdateOnFiber.js
import { SyncLane } from './ReactFiberLane';
import { ConcurrentMode, NoMode } from './ReactTypeMode';
import { HostRoot, ClassComponent } from './ReactWorkTags';
let syncLanePriority = 12;
let NoLanePriority = 0;
let syncQueue = [];
let NoContext = 0;// é»è®¤éæ¹é
let BatchContext = 1; // æ¹é
let executionContext = NoContext; // æ§è¡ç¯å¢ï¼é»è®¤æ¯NoConetxt
/**
* å¨fiberè°åº¦æ´æ°
* @param {z} fiber
* @param {*} lane
* @param {*} eventTime
*/
function scheduleUpdateOnFiber(fiber, lane, eventTime) {
//checkForNestedUpdates();
//warnAboutRenderPhaseUpdatesInDEV(fiber);
// å䏿¾å°è·èç¹ root
var root = markUpdateLaneFromFiberToRoot(fiber, lane);
ensureRootIsScheduled(root, eventTime);
// 妿å½åçæ§è¡ä¸ä¸æç¯å¢æ¯NoContextï¼éæ¹éï¼å¹¶ä¸Mode䏿¯å¹¶åçè¯
if (executionContext === NoContext && (fiber.mode & ConcurrentMode) === NoMode) {
flushSyncCallbackQueue();
}
}
// ä»å½åfiberèç¹ï¼é彿¾å°root
function markUpdateLaneFromFiberToRoot(fiber) {
let parent = fiber.return;
while(parent) {
fiber = parent;
parent = fiber.return;
if (fiber.tag == HostRoot) {
return parent;
}
}
return null;
}
/**
*
* @param {*} root
* @param {*} eventTime
*/
function ensureRootIsScheduled(root, eventTime) {
// æ è®°ä¼å
级ä½ï¼ä½èµéï¼ï¼å¿«è¿æçä»»å¡ï¼ æ è®°ä¸ºæ´æ°
// markStarvedLanesAsExpired(root, currentTime); // Determine the next lanes to work on, and their priority.
// è·åæé«ä¼å
级çlane å½åæ¯ 1 //fiberé
var nextLanes = SyncLane;
// å½åè·èç¹ä¸ï¼æ£å¨æ§è¡çä¼å
级 // ç¬¬ä¸æ¬¡undefined
let existingCallbackPrority = root.callbackPriority;
// è·åæé«çº§å«çèµéçä¼å
级 12
let newCallbackPropority = syncLanePriority; //æç说åºè¯¥çäºæé«çº§å«èµéçä¼å
级
// èµéåä¼å
级ä¸ä¸æ ·ï¼ æå
³ç³»
if (newCallbackPropority === existingCallbackPrority) {
// 乿¯å¨å¹¶å模å¼ï¼å³ä½¿å¨settimeouté乿¯æ¹éçåå
return ;// 妿æ°çæ´æ°åå½åæ ¹èç¹çæ´æ°ç¸çï¼ç´æ¥è¿åï¼å¤ç¨ä¸æ¬¡çæ´æ°?ï¼åä¸éè¦å建æ°çæ´æ°
// TODO å¤ç¨ä¸æ¬¡çæ´æ°
}
sceduleSyncCallback(performSyncWorkOnRoot.bind(null, root));
// 微任塿§è¡
queueMicrotask(flushSyncCallbackQueue);
//
root.callbackPriority = newCallbackPropority;
}
// æ¶é´æ¾å¨å¾®ä»»å¡é
function queueMicrotask() {
}
function flushSyncCallbackQueue() {
syncQueue.forEach(cb => cb());
// æ¸
空éå
syncQueue.length = 0;
}
// å
¶å®å°±æ¯æå½æ°æ¾å¨éåéï¼çå¾
æ§è¡
// è°åº¦
function sceduleSyncCallback(fn) {
syncQueue.push(fn);
}
// å
¶å®å°±æ¯æä»¬çæ£ç渲æä»»å¡
// å
æ¬dom-diff ï¼æ¯è¾èèç¹åæ°èç¹ï¼å¾å°dom-diffç»æ
// æ´æ°
// é½å¨è¿é
// å±äºè°åé¶æ®µ reconciler
function performSyncWorkOnRoot(workInProgress) {
let root = workInProgress;
while (workInProgress) {
console.log('å¼å§æ§è¡è°åä»»å¡');
// ç±»ç»ä»¶
if(workInProgress.tag === ClassComponent) {
let inst = workInProgress.stateNode; // è·åæ¤å¤ç±»ç»ä»¶çå®ä¾
inst.state = processUpdateQueue(inst, workInProgress);
// å¾å°æ°çstateåï¼å°±å¯ä»¥renderå¾å°èædomï¼ä¹ådomdiffï¼æ´æ°dom
inst.render();
}
workInProgress = workInProgress.child;
}
commitRoot(root);
}
// æäº¤
function commitRoot(root) {
// æ ¹èç¹çä¼å
级设置为é»è®¤å¼
root.callbackPriority = NoLanePriority;
}
/**
* æ ¹æ®èç¶æåæ´ç»éåï¼è®¡ç®æ°ç¶æ
* @param {*} inst
* @param {*} workInProgress
*/
function processUpdateQueue(inst, fiber) {
return fiber.update.reduce((state, update) => {
let payload = update.payload;
if (typeof update.payload === 'function') {
payload = update.payload(state);
}
return {
...state,
...payload
}
}, inst.state);
}
// React.unstabe_batchUpdate
export function batchUpdate(fn) {
let preContext = executionContext;
executionContext |= BatchContext;
fn();
executionContext = preContext;
}
export default scheduleUpdateOnFiber;