-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: xsahxl <[email protected]>
- Loading branch information
Showing
7 changed files
with
128 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
# diff 和 fiber | ||
|
||
## 是什么? | ||
|
||
diff 算法是通过对比新旧虚拟 dom 精确的找出变化之处,然后同步到真实的 dom 上。 | ||
|
||
## 原理 | ||
|
||
react diff 算法 主要遵循三个层级的策略 | ||
|
||
- tree 层级 | ||
- component 层级 | ||
- element 层级 | ||
|
||
### tree 层级 | ||
|
||
DOM 节点跨层级的操作不做优化,只会对相同层级的节点进行比较 | ||
 | ||
|
||
只有删除、创建操作,没有移动操作,如下图: | ||
 | ||
|
||
react 发现新树中,R 节点下没有了 A,那么直接删除 A,在 D 节点下创建 A 以及下属节点 | ||
|
||
上述操作中,只有删除和创建操作 | ||
|
||
### component 层级 | ||
|
||
如果是同一个类的组件,则会继续往下 diff 运算,如果不是一个类的组件,那么直接删除这个组件下的所有子节点,创建新的 | ||
|
||
 | ||
|
||
当 component D 换成了 component G 后,即使两者的结构非常类似,也会将 D 删除再重新创建 G | ||
|
||
### element 层级 | ||
|
||
对于比较同一层级的节点们,每个节点在对应的层级用唯一的 key 作为标识 | ||
|
||
提供了 3 种节点操作,分别为 INSERT_MARKUP(插入)、MOVE_EXISTING (移动)和 REMOVE_NODE (删除) | ||
|
||
## fiber | ||
|
||
React 16 以前递归对比虚拟 DOM 树的方案有一个明显的问题:`阻塞主线程`。旧的 React 架构中,Diff 算法和组件更新都是同步执行的。这意味着一旦更新开始,React 会一直占用主线程直到整个更新过程完成,这就可能导致浏览器无法响应用户操作,界面卡顿等现象 | ||
|
||
React 16 为了优化性能,会先把虚拟 DOM 树转换成 Fiber,也就是从树转换成链表,再基于 Fiber 进行渲染。这个过程分成两个阶段: | ||
|
||
- reconcile(可中断) :从虚拟 DOM 转换成 Fiber,并给需要操作的节点打上标记。 | ||
- commit(不可中断) :对有标记的 Fiber 节点进行操作。 | ||
|
||
### 建立 fiber | ||
|
||
第一次渲染不需要 diff,直接讲虚拟 dom 转为 fiber | ||
|
||
 | ||
|
||
### 更新 fiber | ||
|
||
尽可能复用旧的 fiber 来更新本次的 fiber | ||
|
||
 | ||
|
||
具体实现分为两次遍历 | ||
|
||
- 第一次遍历:`复用 位置和内容都相同的节点`。方式是对比虚拟 dom 和旧的 fiber,如果可以复用就继续处理下一个节点,否则就结束遍历。 | ||
如上图,相比初始的 fiber,A,B,C 都是完全没变的,直接复用,在往下走原本是 E,但现在变成了 D,发现不能复用,直接返回 | ||
|
||
- 第二次遍历:`把剩下的内容填上`, 方法是把剩余的旧 fiber 节点做成一个 map,然后遍历新 dom 树,构建新 fiber 的时候查查 map,能复用的就复用,用不了就新建。如上图,构建 D、F、H 的时候发现旧 Fiber 里有,那么可以拿过来复用,M 以前没有,那就新建一个。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
# 虚拟 dom | ||
|
||
## 虚拟 dom 是什么 | ||
|
||
组件 render 返回的对象就是 vdom,一般包含标签名称,标签属性,事件监听和子元素等。 | ||
|
||
## 虚拟 dom 有什么优点 | ||
|
||
- 能减少不必要的 dom 操作 | ||
|
||
- 减少 dom 更新的次数 | ||
你用传统的原生 api 或 jQuery 去操作 DOM 时,浏览器会从构建 DOM 树开始从头到尾执行一遍流程 | ||
当你在一次操作时,需要更新 10 个 DOM 节点,浏览器没这么智能,收到第一个更新 DOM 请求后,并不知道后续还有 9 次更新操作,因此会马上执行流程,最终执行 10 次流程 | ||
而通过 VNode,同样更新 10 个 DOM 节点,虚拟 DOM 不会立即操作 DOM,而是将这 10 次更新的 diff 内容保存到本地的一个 js 对象中,最终将这个 js 对象一次性 attach 到 DOM 树上,避免大量的无谓计算 | ||
|
||
- 减少 dom 更新的范围 | ||
通过 diff 算法,能够只更新被修改的 DOM 节点,而非全部重绘 | ||
|
||
- 能跨平台渲染,比如 react native | ||
虚拟 DOM 最大的优势在于抽象了原本的渲染过程,实现了跨平台的能力,而不仅仅局限于浏览器的 DOM,可以是安卓和 IOS 的原生组件,可以是近期很火热的小程序,也可以是各种 GUI | ||
|
||
## 虚拟 dom 怎么实现 | ||
|
||
- 虚拟 dom 一般用 js 对象来表示,比如 | ||
|
||
```js | ||
{ | ||
tag: 'div', | ||
attrs: { | ||
id: 'container', | ||
className: 'container' | ||
}, | ||
children: [ | ||
{ | ||
tag: 'span', | ||
attrs: { | ||
className: 'red' | ||
}, | ||
children: ['Hello, world!'] | ||
} | ||
] | ||
} | ||
``` | ||
|
||
## 虚拟 dom 有什么缺点 | ||
|
||
需要额外的创建函数,比如 CreateElement 或 h,但可以通过 jsx 来简化成 xml 写法 |