巨大的用户群体绝不仅意味着金山银山,还意味着责任如山。
今日学习内容
1、https://www.youtube.com/watch?v=EVFZazcxAbo&t=4112s
今日笔记
Commit阶段工作流简析
- before mutation阶段,这个阶段DOM节点还没有被渲染到界面上去
- mutation,这个阶段负责DOM节点的渲染
- layout,这个阶段处理DOM渲染完毕之后的收尾逻辑
它还会把fiberRoot的current指针指向workInProgress Fiber树
performSyncWorkOnRoot
workLoopSync
performUnitOfWork
beginWork
completeWork
completeUnitOfWork
reconcileChildFibers
concurrent模式(异步渲染)下的“时间切片”和“优先级”实现
“双缓存”模式
在React中双缓冲模式能够帮我们较大限度地实现Fiber节点的复用从而减少性能方面的开销
completeWork的工作原理:
current树与workInProgress树可以对标“双缓存”模式下的两套缓冲数据:
当current树呈现在用户眼前时,所有的更新都会由workInProgress树来承接
workInProgress树将在内存里完成改变
时间切片关键代码片段:
1 2 3 4 5
| function workLoopConcurrent() { while (workInProgress !== null && !shouldYield()) { performUnitOfWork(workInProgress); } }
|
shouldYield() 是 时间切片的核心判断条件。
1 2 3
| function shouldYieldToHost() { return getCurrentTime() >= deadline; }
|
deadline 是当前帧的截止时间(由 requestAnimationFrame 或 MessageChannel 推动),当当前时间超过 deadline,就会返回 true,中断渲染,让出主线程。
[开始构建 Fiber 树]
↓
[workLoopConcurrent]
↓
while (workInProgress && !shouldYield()) {
↓
performUnitOfWork(unit)
}
↓
[如果 shouldYield() === true]
→ 让出主线程
→ 等下一帧继续(通过 MessageChannel 触发 flushWork)
优先级调度:
- 通过调用unstable_scheduleCallback来发起调度
- 结合任务的优先级信息为其执行不同的调度逻辑
源码解析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| function unstable_scheduleCallback(priorityLevel, callback, options){ var currentTime = exports.unstable_now(); var startTime;
if(typeof options === 'object' && options !== null){ var delay = options.delay;
if(typeof delay === 'number' && delay > 0){ startTime = currentTime + delay; } else { startTime = currentTime; } }else{ startTime = currentTime; }
var timeout;
switch(priorityLevel){ case ImmediatePriority: timeout = IMMEDIATE_PRIORITY_TIMEOUT; break; case UserBlockingPriority: timeout = USER_BLOCKING_PRIORITY_TIMEOUT; break; case NormalPriority: timeout = NORMAL_PRIORITY_TIMEOUT; break; case LowPriority: timeout = LOW_PRIORITY_TIMEOUT; break; case IdlePriority: timeout = IDLE_PRIORITY_TIMEOUT; break; default: throw new Error('Unknown priority level.'); }
var expirationTime = startTime + timeout;
var newTask = { id: ++taskIdCounter, callback: callback, priorityLevel: priorityLevel, startTime: startTime, expirationTime: expirationTime, sortIndex: -1, }
if(startTime > currentTime){ newTask.sortIndex = startTime; push(timerQueue, newTask);
if(peek(taskQueue) === null && peek(timerQueue) === newTask) { .... requestHostTimeout(handleTimeout, startTime - currentTime); } }else{ newTask.sortIndex = expirationTime; push(taskQueue, newTask); requestHostCallback(flushWork); } return newTask; }
|


