react之所以可以快速更新dom,在於react可以對比虛擬dom,找到差異後,只更新改變的部分。
diff演算法有很多,比如dfs演算法o(n^3) > cito.js> kivi.jso(n^2)
對於react,fb通過大膽的策略,滿足了大多數的效能最大化,將o(n3)複雜度的問題成功的轉換成了o(n),並且後面對於同級節點移動,犧牲一定的dom操作,演算法的複雜度也才打到o(max(m,n))。
react原始碼(0.3)實現:
updatemultichild: function(nextchildren, transaction) else if (nextchildren && !this._renderedchildren) ; // lazily allocate backing store with nothing
} else if (!nextchildren && this._renderedchildren) ;
}var rootdomiddot = this._rootnodeid + '.';
var markupbuffer = null; // accumulate adjacent new children markup.
var numpendinginsert = 0; // how many root nodes are waiting in markupbuffer
var loopdomindex = 0; // index of loop through new children.
var curchildrendomindex = 0; // see (comment 1)
for (var name in nextchildren)
// 獲取當前節點與要渲染的節點
var curchild = this._renderedchildren[name];
var nextchild = nextchildren[name];
// 是否兩個節點都存在,且型別相同
if (shouldmanageexisting(curchild, nextchild))
numpendinginsert = 0;
// 如果找到當前要渲染的節點序號比最大序號小,則移動節點
/** 在0.3中,沒有根據key做diff,而是通過object中的key作為索引
* 比如替換成
* b._domindex = 1挪到loopdomindex = 1的位置,就是原地不動
a._domindex = 0挪到loopdomindex = 2的位置,也就是和c換位
*/ if (curchild._domindex < curchildrendomindex)
curchildrendomindex = math.max(curchild._domindex, curchildrendomindex);
// 遞迴更新子節點props,呼叫子節點dom-diff...
!nextchild.props.isstatic &&
curchild.receiveprops(nextchild.props, transaction);
curchild._domindex = loopdomindex;
} else
// 當前不存在,下個節點存在, 執行插入,渲染下個節點
if (nextchild)
}loopdomindex = nextchild ? loopdomindex + 1 : loopdomindex;
}// 執行插入操作,插入位置計算方式如下:
// 要渲染的節點位置-要插入的節點個數:比如當前要渲染的節點index=3,當前節點只有乙個,也就是index=1。
// 如1
渲染成123
// 那麼從2
開始就開始加入buffer,最終buffer內容為2
3 // 那麼要插入的位置為 3 - 1 = 2。我們以1
為1,就是把buffer插入2的位置,也就是1
後面 if (markupbuffer)
// 迴圈老節點
for (var childname in this._renderedchildren)
var child = this._renderedchildren[childname];
// 當前節點存在,下個節點不存在,刪除
if (child && !nextchildren[childname])
}// 一次提交所有操作
this.processchilddomoperationsqueue();
}
diff和dom更新關聯圖:
三個大膽策略詳解:
只會對同一層次的節點進行比較,如果節點不存在直接刪除建立
同一型別的元件繼續tree diff比較,不同型別的元件直接刪除重建。
三種方法:插入,移動,刪除
舉個例子:
state =
componentdidmount = () => )},5000)
}//render兩種情況
//一種key = ) }
//一種key = ) }
上面例子中第一種情況,在testlist改變後:三個節點都會更新
第二種情況,會先刪除,再移動,再插入
為什麼會有上述兩種情況的區別呢?
對於第一種情況:
key = 在更新前後是相同的,都是1,2,3
但是對比,key相同時,元素不同,則刪除插入
對於第二種情況;
key = key分別是 'll','ww','kk' ,更新後虛擬dom key分別是kk ll ww,在進行element diff時,發現kk元素節點在更新前後是相同的,無需建立,會進行移動
說明:對於第一種情況,其實和沒有key是一樣的,除非其順序和key保持一致;
針對這一現象,react 提出優化策略:允許開發者對同一層級的同組子節點,新增唯一 key 進行區分,雖然只是小小的改動,效能上卻發生了翻天覆地的變化!
第二種情況的key和順序無關,可以找到更新前後沒有更改的元素節點。
總結:參考:
React Diff 演算法及效能優化
setstate是非同步操作,多次setstate合併成一次setstate,減少 diff 比對 兩個虛擬 dom 進行比對時,從上往下進行比對,如果同一層比對存在差異時就不會繼續進行比對 引入 key 值提高比對效能,其中 key 值最好不要為 index,應該是固定 唯一的值,比如 item ...
A 演算法詳解
第一部分 a 演算法簡介 寫這篇文章的初衷是應乙個的要求,當然我也發現現在有關人工智慧的中文站點實在太少,我在這裡 拋磚引玉,希望大家都來熱心的參與。還是說正題,我先拿a 演算法開刀,是因為a 在遊戲中有它很典型的用法,是人工智慧在遊戲中的代表。a 演算法在人工智慧中是一種典型的啟發式搜尋演算法,為...
A 演算法詳解
a 演算法的基本原理 a star演算法是一種靜態路網中求解最短路徑最有效的直接搜尋方法,也是解決許多搜尋問題的有效演算法。演算法中的距離估算值與實際值越接近,最終搜尋速度越快。f i g i h i 以上式子中 g i 表示從起點到當前節點已經付出的代價,這個是準確的 a 演算法最重要的是估價函式...