React setState 運(yùn)行機(jī)制
- setState是同步操作,采用批處理機(jī)制
- react采用了事務(wù)transaction設(shè)計(jì)思想
- vue采用的瀏覽器的event-loop機(jī)制: 主隊(duì)列,異步隊(duì)列(微隊(duì)列、宏隊(duì)
列),因此說vue是依賴了JS語言的特性,而不像大廠出品的react
先看一段代碼,并判斷輸出值
constructor(props){
super(props);
this.state = {
count: 0
};
}
componentDidMount(){
let me = this;
me.setState({
count: me.state.count + 1
});
console.log('第1次:', me.state.count);
me.setState({
count: me.state.count + 1
});//1
console.log('第2次:', me.state.count);
setTimeout(function(){
me.setState({
count: me.state.count + 1
});
console.log('第3次:', me.state.count);
}, 0);
setTimeout(function(){
me.setState({
count: me.state.count + 1
});
console.log('第4次:', me.state.count);
}, 0);
}
render() {
return (
<div className="App">
<p>{this.state.count}</p>
</div>
);
}
}
export default App;
//頁(yè)面顯示 3,輸出結(jié)果如下:
第1次:0
第2次:0
第3次:2
第4次:3
為什么不是 1 2 3 4呢? react采用批處理,因此react只會(huì)執(zhí)行最后一個(gè)setState,前面的setState被react忽略掉;由于react無法將setTimeout加入到批處理當(dāng)中,因此后面兩個(gè)setTimeout里面setState單獨(dú)執(zhí)行,進(jìn)而批處理剩下第二個(gè)setState,故而第1次:0
為什么不是 0 1 2 3呢? react采用事務(wù)的機(jī)制來處理setState,要先收集setState要做的事情,然后再之后的某一個(gè)時(shí)間點(diǎn)進(jìn)行統(tǒng)一處理,注意:setState是同步的操作,是在主線程運(yùn)行的,但它被抽出來了,執(zhí)行事務(wù)的機(jī)制,先收集,然后往下走,相對(duì)來說,給我們的感覺像是異步的,因此第2次:0
接下來就是 第3次:2 第4次:3,setTimeOut不參與批處理和事務(wù)機(jī)制,因此就直出了
V15 版本的問題
由于react事務(wù)統(tǒng)一處理機(jī)制(統(tǒng)一收集,主線程統(tǒng)一執(zhí)行),如果setState
的內(nèi)容過大時(shí),render時(shí)會(huì)造成頁(yè)面的卡死,這一點(diǎn)在16版本進(jìn)行了優(yōu)化
- vue是異步線程的操作,因此不會(huì)卡死
V16 版本的優(yōu)化
為了解決15版本卡死的問題,V16提出了Fiber,已經(jīng)更新的react-dom React Fiber
- Reconciler即Virtul DOM, 用于計(jì)算新老View的差異(dom-diff)
- React 16之前的 Reconciler 叫 Stack Reconciler
- Fiber是React新的Reconciler,F(xiàn)iber是一次重量級(jí)的核心架構(gòu)的更換
Reconciler和render兩個(gè)概念引出了phase概念
- phase指的是React組件渲染時(shí)的階段
- Reconciler階段: 依序遍歷組件,通過diff算法,判斷組件是否需要更新,給需要更新的組件加上tag,遍歷在完成后,將所有帶有tag的組件加到一個(gè)數(shù)組中,這個(gè)階段的任務(wù)可以被打斷,先執(zhí)行新的重要任務(wù),待執(zhí)行完畢后,再回來繼續(xù)Reconciler
Commit階段: 根據(jù)在Reconciler階段生成的數(shù)組,遍歷更新DOM,這個(gè)階段要一次性執(zhí)行完
image.png
Filber Reconciler VS Stack Reconciler
- Stack: 以前react渲染相關(guān)的事務(wù)是連續(xù)的,一旦開始,就會(huì)在主線程渲染,其他任務(wù)必須等待,導(dǎo)致了主線程被阻塞,影響性能。
- Fiber: 現(xiàn)在react事務(wù)是由一系列Fiber的更新組成,因此可以在多個(gè)幀中斷斷續(xù)續(xù)的更細(xì)Fiber,最后commit變化(將原來的整個(gè)Virtul DOM的更新任務(wù)拆分成一個(gè)個(gè)的小任務(wù),每次做完一個(gè)小任務(wù)后,放棄一下自己的執(zhí)行將主線程空閑出來,看看有沒有其他任務(wù),如果有,就暫停本次任務(wù),執(zhí)行其他任務(wù),如果沒有,就繼續(xù)下一個(gè)任務(wù))
- 總結(jié): V16把以前的一個(gè)大事務(wù)改為拆分成一個(gè)個(gè)小事務(wù),標(biāo)記為tag,優(yōu)先級(jí)高的就打斷事務(wù)的執(zhí)行,釋放主線程
