2021-03-03 React原理解析02
协调-reconciliation
设计动力
调用React的render()方法会创建一颗由React元素组成的树,在下一次state、props或context更新时候,相同的render()方法会返回一颗不同的树。React需要基于这两颗树之间的差别来判断如何有效的更新UI以保证当前UI与最新的树保持同步
React提出了一套O(n)-n是树中元素的数量,启发式算法(diff算法):
1、两个不同类型的元素会产生出不同的树
2、开发者可以通过key
prop属性来暗示哪些子元素在不同的渲染下能保持稳定
diff算法-算法复杂度O(n)
diff的策略:
1、同级比较,Web UI中DOM节点跨层级的移动操作特别少,可以忽略不计
2、拥有不同类型的两个组件将会生成不同的树形结构
例如:div->p,CompA->CompB
3、开发者可以通过key
prop属性来暗示哪些子元素在不同的渲染下能保持稳定
diff过程
对比两个虚拟dom时会有三种操作:删除、替换和更新
vnode是现在的虚拟dom,newVnode是新虚拟dom
删除:newVnode不存在时
替换:vnode和newVnode类型不同或key不同时
更新:有相同类型和key时,但vnode和newVnode不同时
fiber
为什么需要fiber
1、对于大型项目,组件树会很大,这个时候递归遍历的成本就会很高,会造成主线程被持续占用,结果就是主线程上的布局、动画等周期性任务就无法立即得到处理,造成视觉上的卡顿,影响用户体验
2、任务分解就是解决上面的问题
3、增量渲染(把渲染任务拆分成块,匀到多帧)
4、更新时能够暂停,终止,复用渲染任务
5、给不同的类型的更新赋予优先级
6、并发方面的基础能力
7、更流畅
什么是fiber
fiber是指组件上将要完成或者已经完成的任务,每个组件可以一个或者多个fiber,它的数据结构类似于链表,有指针指向,表示vnode节点
实现fiber
window.requestIdleCallback(callback[, options])
此方法将在浏览器的空闲时段内调用函数队列。这使得开发者能够在事件循环上执行后台和优先级工作,而不会影响延迟关键事件,如动画和输入响应。函数一般会按先进先调用的顺序执行,然而,如果回调函数指定了执行超时时间timeout
,则有可能为了在超时前执行函数而打乱顺序
可以在空闲回调函数中调用requestIdleCallback()
,以便在下一次通过事件循环之前调度另一个回调
Fiber是React 16中新的协调引擎,它的主要目的是使Virtual DOM可以进行增量渲染
一个更新过程可能会被打断,所以React Fiber一个更新过程被分为两个阶段:
第一个阶段:Reconciliation Phase
第二个阶段:Commit Phase
有fiber的react-dom.js文件
/**
* vnode 虚拟DOM
* node 真实DOM
*/
// 根节点 fiber
let wipRoot = null;
function render(vnode, container) {
/* console.log("vnode", vnode);
// vnode->node
const node = createNode(vnode);
// node 插入到container中
container.appendChild(node); */
wipRoot = {
type: "div",
props: {
children: {
...vnode } },
stateNode: container
};
nextUnitWork = wipRoot;
}
function isString(str) {
return typeof str === "string";
}
// 根据vnode,生成node
function createNode(workInProgress) {
let node = document.createElement(workInProgress.type);
updateNode(node, workInProgress.props);
return node;
}
// 更新属性
function updateNode(node, nextVal) {
Object.keys(nextVal)
// .filter(k => k !== "children")
.forEach(k => {
if (k