Skip to content

Commit 1a6d749

Browse files
committed
add: comments
1 parent f86d5e9 commit 1a6d749

File tree

13 files changed

+187
-9080
lines changed

13 files changed

+187
-9080
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
# dependencies
44
/node_modules
5+
/pics
56
/.pnp
67
.pnp.js
78
.idea

docs/Concurrent模式下React的更新行为/高优先级任务插队.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -267,9 +267,9 @@ concurrent模式下的lanes:/* */ 0b111111111111
267267
- 属于concurrent模式的优先级:调用scheduleCallback将任务以上面获取到的新任务优先级去加入调度。
268268

269269
这里有两点需要说明:
270-
1. 为什么新旧任务的优先级不相等,那么新任务的优先级一定高于旧任务?
270+
1. 为什么新旧任务的优先级如果不相等,那么新任务的优先级一定高于旧任务?
271271
这是因为每次调度去获取任务优先级的时候,都只获取root.pendingLanes中最紧急的那部分lanes对应的优先级,低优先级的update持有的lane对应的优先级是无法被获取到的。
272-
通过这种办法,可以将来自同一事件中的多个更新收敛到一个任务中去执行,例如在一个事件中多次调用setState:
272+
通过这种办法,可以将来自同一事件中的多个更新收敛到一个任务中去执行,言外之意就是同一个事件触发的多次更新的优先级是一样的,没必要发起多次任务调度。例如在一个事件中多次调用setState:
273273
```javascript
274274
class Demo extends React.Component {
275275
state = {
@@ -317,7 +317,7 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) {
317317
root === workInProgressRoot ? workInProgressRootRenderLanes : NoLanes,
318318
);
319319

320-
// 获取renderLanes对应的优先级,它会作为新任务的优先级
320+
// 获取renderLanes对应的任务优先级
321321
const newCallbackPriority = returnNextLanesPriority();
322322

323323
if (nextLanes === NoLanes) {
@@ -363,12 +363,12 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) {
363363
} else {
364364
// concurrent模式的渲染会走这里
365365

366-
// 根据lanePriority获取Scheduler的调度优先级
366+
// 根据任务优先级获取Scheduler的调度优先级
367367
const schedulerPriorityLevel = lanePriorityToSchedulerPriority(
368368
newCallbackPriority,
369369
);
370370

371-
// 将React的更新任务放到Scheduler中去调度,调度优先级是schedulerPriorityLevel
371+
// 计算出调度优先级之后,开始让Scheduler调度React的更新任务
372372
newCallbackNode = scheduleCallback(
373373
schedulerPriorityLevel,
374374
performConcurrentWorkOnRoot.bind(null, root),
@@ -381,8 +381,8 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) {
381381
}
382382
```
383383

384-
`ensureRootIsScheduled`实际上是在任务调度层面整合了高优先级任务的插队和任务饥饿问题的关键逻辑,这只是宏观层面的决策,决策背后的诱因是React处理更新时
385-
对于不同优先级update的取舍以及root上pendingLanes的标记操作,这需要我们下沉到更新任务的执行过程中
384+
`ensureRootIsScheduled`实际上是在任务调度层面整合了高优先级任务的插队和任务饥饿问题的关键逻辑,这只是宏观层面的决策,决策背后的原因是React处理更新时
385+
对于不同优先级的update的取舍以及对root.pendingLanes的标记操作,这需要我们下沉到执行更新任务的过程中
386386

387387
# 处理更新
388388
一旦有更新产生,update对象就会被放入updateQueue并挂载到fiber节点上。构建fiber树时,会带着renderLanes去处理updateQueue,在beginWork阶段,对于类组件

docs/fiberTask4.gif

3.35 MB
Loading

docs/render阶段/beginWork阶段/setState异步原理/multiSetState.json

Lines changed: 0 additions & 8783 deletions
This file was deleted.

docs/render阶段/completeWork/completeWork.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# 概述
2-
每个WIP节点都会经历两个阶段:beginWork和completeWork。节点进入complete的前提是已经完成了beginWork。这个时候拿到的WIP节点都是
2+
每个fiber节点在更新时都会经历两个阶段:beginWork和completeWork。节点进入complete的前提是已经完成了beginWork。这个时候拿到的WIP节点都是
33
经过diff算法调和过的,也就意味着对于某个WIP节点来说它fiber类型的形态已经基本确定了,但除此之外还有两点:
44

55
* 目前只有fiber形态变了,对于原生DOM组件(HostComponent)和文本节点(HostText)的fiber来说,对应的DOM节点(fiber.stateNode)并未变化。

docs/setStateOverview.md

Lines changed: 0 additions & 152 deletions
This file was deleted.

docs/概述.md

Lines changed: 37 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,38 @@
1-
React 进入调度有两种途径:挂载和更新,可以把他们理解成任务,调度的目的是依据优先级对任务进行合理的安排。
2-
3-
React 的Concurrent模式解决的问题是帮助应用保持响应,而交互和更新任务是互斥的。交互的最终结果是产生更新,进而生成任务进入调度流程。
4-
5-
如果此时已有任务在进行,但优先级低于新任务,那么它将会被取消,重新对新任务安排一个调度。
6-
7-
这里说的任务在React的内在行为上,就是从root开始,进入工作循环,构建workInProgress树。
8-
9-
任务调度
10-
11-
工作循环
12-
概述
13-
执行工作单元
14-
render阶段
15-
beginWork
16-
处理更新
17-
diff操作
18-
completeWork
19-
commit阶段
20-
commitWork
21-
22-
更新的完整过程
23-
24-
25-
金字塔结构
26-
27-
React 第一次渲染: ReactDOM.render
28-
数据准备 调度 workLoop
29-
30-
React 更新: ReactDOM.render
31-
事件系统 调度 workLoop
32-
33-
34-
1+
React原理,从更新说起。
2+
3+
作为一个构建用户界面的库,React的核心始终围绕着更新这一个重要的目标,将更新和极致的用户体验结合起来是React团队一直在努力的事情。为什么React可以将用户体验做到这么好?我想这是基于以下两点原因:
4+
5+
* Fiber架构和Scheduler出色的调度模式可以实现异步可中断的更新行为。
6+
* 优先级机制贯穿更新的整个周期
7+
8+
下面我们基于这两点展开,在解读原理之前,对一些概念先有个基础认知。
9+
# Fiber是什么
10+
Fiber是什么?它是React的最小工作单元,在React的世界中,一切都可以是组件。在普通的HTML页面上,人为地将多个DOM元素整合在一起可以组成一个组件,HTML标签可以是组件(HostComponent),
11+
普通的文本节点也可以是组件(HostText)。每一个组件就对应着一个fiber节点,许多个fiber节点互相嵌套、关联,就组成了fiber树,正如下面表示的Fiber树和DOM的关系一样:
12+
```
13+
Fiber树 DOM树
14+
15+
div#root div#root
16+
| |
17+
<App/> div
18+
| / \
19+
div p a
20+
/ ↖
21+
/ ↖
22+
p ----> <Child/>
23+
|
24+
a
25+
26+
```
27+
一个DOM节点一定对应着一个Fiber节点,但一个Fiber节点却不一定有对应的DOM节点。
28+
29+
每一个fiber节点都可能会产生更新,每当有更新的时候,React都会从root开始重新构建fiber树。这个行为,就是React的更新任务。对Fiber树来说,一旦有一个更新任务,它就会经历一个深度优先遍历的过程,
30+
依照现有fiber树构建一个新的fiber树,现有fiber树称为current树,构建的新fiber树称为workInProgress树。整个fiber树会经历向下遍历以及向上回溯的两个过程,所以每个fiber节点,也会经历两个过程:
31+
**beginWork****completeWork****构建过程中会有一个workInProgress的指针记录下当前构建到哪个fiber节点**,这是React更新任务可恢复的重要原因之一。fiber树的构建过程如下动图:
32+
33+
![fiberTask](http://neroht.com/fiberTask4.gif)
34+
35+
36+
# 双缓冲机制
37+
双缓冲机制
3538

0 commit comments

Comments
 (0)