React中文文档 doc.react-china.org/javascript
前端开发中,原生JS对DOM的频繁操做每每是使人头痛而且十分影响性能的; 而React在设计之初就考虑到了这种需求并将其做为重点,因而也就有了这里要说的Diff算法;能够说Diff是React性能的保障html
Diff算法是一种经常使用的对比差别的算法,但传统Diff算法对于DOM树的比较是比较吃力的,下面附上一份简易版Diff算法(源代码来自:blog.csdn.net/qq_26708777…)前端
let result = [];
// 比较叶子节点
const diffLeafs = function (beforeLeaf, afterLeaf) {
// 获取较大节点树的长度
let count = Math.max(beforeLeaf.children.length, afterLeaf.children.length);
// 循环遍历
for (let i = 0; i < count; i++) {
const beforeTag = beforeLeaf.children[i];
const afterTag = afterLeaf.children[i];
// 添加 afterTag 节点
if (beforeTag === undefined) {
result.push({ type: "add", element: afterTag });
// 删除 beforeTag 节点
} else if (afterTag === undefined) {
result.push({ type: "remove", element: beforeTag });
// 节点名改变时,删除 beforeTag 节点,添加 afterTag 节点
} else if (beforeTag.tagName !== afterTag.tagName) {
result.push({ type: "remove", element: beforeTag });
result.push({ type: "add", element: afterTag });
// 节点不变而内容改变时,改变节点
} else if (beforeTag.innerHTML !== afterTag.innerHTML) {
if (beforeTag.children.length === 0) {
result.push({
type: "changed",
beforeElement: beforeTag,
afterElement: afterTag,
html: afterTag.innerHTML
});
} else {
// 递归比较
diffLeafs(beforeTag, afterTag);
}
}
}
return result;
}
复制代码
既然传统的Diff算法对于DOM操做有性能上的缺点,那么React又是如何解决这一问题的呢?下面看一段React代码java
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
class App extends Component {
render() {
return (
<div className="app"> <h1>Find My Fruit</h1> </div>
)
}
}
ReactDOM.render(
<App />, document.getElementById('root') ); 复制代码
须要特别注意, render 执行的结果获得的不是真正的 DOM 节点. 结果仅仅是轻量级的 JavaScript 对象, 咱们称之为 virtual DOM.react
· Web UI 中DOM节点跨层级的移动操做特别少,能够忽略不计算法
· 拥有相同类的两个组件将会生成类似的树形结构,拥有不一样类的两个组件将会生成不一样的树形结构。app
· 对于同一层级的一组子节点,它们能够经过惟一id进行区分。dom
基于策略一,WebUI中DOM节点跨层级的移动操做少的能够忽略不计,React对Virtual DOM树进行了层级控制,只会对相同层级的DOM节点进行比较,即同一个父元素下的全部子节点,当发现节点已经不存在了,则会删除掉该节点下全部的子节点,不会再进行比较。这样只须要对DOM树进行一次遍历,就能够完成整个树的比较。复杂度变为O(n);性能
那么,若是真的出现跨层及操做,React是如何表现的呢? 以下图所示,A节点及其子节点被整个移动到D节点下面去,因为React只会简单的考虑同级节点的位置变换,而对于不一样层级的节点,只有建立和删除操做,因此当根节点发现A节点消失了,就会删除A节点及其子节点,当D发现多了一个子节点A,就会建立新的A做为其子节点。 此时,diff的执行状况是:ui
remove A-> add A-> add B ->add C
这种状况天然是比较消耗性能的,因此在开发React组件时要尽可能保证的DOM结构的稳定,尽可能避免出现跨层级操做
React 只会匹配相同 class 的 component.说白了也就是只会对同一类型的组件进行比较,而对于不一样的类型组件,则放弃比较,直接删掉旧的添加新的
好比, 若是有个 Header 被 ExampleBlock 替换掉了, React 会删除掉 header 再建立一个 example block. 咱们不须要化宝贵的时间去匹配两个不大可能有类似之处的 component.
假设咱们有个 component, 一个循环渲染了 5 个 component, 随后又在列表中间插入一个新的 component.这时候会如何操做呢?