react之setState運(yùn)行機(jī)制

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í)行,釋放主線程
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容