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.這時候會如何操做呢?