React機(jī)制和diff算法

1、setState機(jī)制

理想情況下:

setState是異步的泳猬,調(diào)用setState只會(huì)提交一次state修改到隊(duì)列中,不會(huì)直接修改this.state宇植。等到滿足一定條件時(shí)得封,react會(huì)合并隊(duì)列中的所有修改,觸發(fā)一次update流程指郁,更新this.state

由于setState會(huì)觸發(fā)update過(guò)程忙上,因此在update過(guò)程中必經(jīng)的生命周期中調(diào)用setState會(huì)存在循環(huán)調(diào)用的風(fēng)險(xiǎn),另外用于監(jiān)聽state更新完成坡氯,可以使用setState方法的第二個(gè)參數(shù)晨横,回調(diào)函數(shù)。在這個(gè)回調(diào)中讀取this.state就是已經(jīng)批量更新后的結(jié)果

特殊情況下:

(1)mount流程中調(diào)用setState箫柳,不會(huì)進(jìn)入update流程手形,隊(duì)列在mount時(shí)合并修改并render

(2)setTimeout/Promise回調(diào)中調(diào)用setState,將不會(huì)進(jìn)行隊(duì)列的批更新悯恍,而是直接觸發(fā)一次update流程


2库糠、diff算法

三條策略:

(1)WebUI中DOM節(jié)點(diǎn)跨節(jié)點(diǎn)的操作特別少,可以忽略不計(jì)

(2)擁有相同類的組件會(huì)擁有相似的DOM結(jié)構(gòu)。擁有不同類的組件會(huì)生成不同的DOM結(jié)構(gòu)瞬欧。

(3)同一層級(jí)的子節(jié)點(diǎn)贷屎,可以根據(jù)唯一的ID來(lái)區(qū)分

針對(duì)這三個(gè)策略,react diff實(shí)施的具體策略是:

(1)diff對(duì)樹進(jìn)行分層比較艘虎,只對(duì)比兩棵樹同級(jí)別的節(jié)點(diǎn)唉侄。跨層級(jí)移動(dòng)節(jié)點(diǎn)野建,將會(huì)導(dǎo)致節(jié)點(diǎn)刪除属划,重新插入,無(wú)法復(fù)用

(2)diff對(duì)組件進(jìn)行類比較候生,類相同的遞歸diff子節(jié)點(diǎn)同眯,不同的直接銷毀重建。diff對(duì)同一層級(jí)的子節(jié)點(diǎn)進(jìn)行處理時(shí)唯鸭,會(huì)根據(jù)key進(jìn)行簡(jiǎn)要的復(fù)用须蜗。兩棵樹中存在相同key的節(jié)點(diǎn)時(shí),只會(huì)移動(dòng)節(jié)點(diǎn)

另外目溉,在對(duì)比同一層級(jí)的子節(jié)點(diǎn)時(shí)明肮,diff算法會(huì)以新樹的第一個(gè)子節(jié)點(diǎn)作為起點(diǎn)遍歷新樹,尋找舊樹種與之相同的節(jié)點(diǎn)缭付。如果節(jié)點(diǎn)存在晤愧,則移動(dòng)位置,如果不存在蛉腌,則新建一個(gè)節(jié)點(diǎn)。在這個(gè)過(guò)程中只厘,維護(hù)了一個(gè)字段lastIndex烙丛,這個(gè)字段表示已遍歷的所有新樹子節(jié)點(diǎn)在舊樹種最大的index。在移動(dòng)操作時(shí)羔味,只有舊的index小于lastIndex的才會(huì)移動(dòng)

3河咽、正確使用diff算法

(1)不適用跨層級(jí)移動(dòng)節(jié)點(diǎn)的操作

(2)對(duì)于條件渲染多個(gè)節(jié)點(diǎn)時(shí),盡量采用隱藏等方式切換節(jié)點(diǎn)赋元,而不是替換節(jié)點(diǎn)

(3)盡量避免將后面的子節(jié)點(diǎn)移動(dòng)到前面的操作忘蟹,當(dāng)節(jié)點(diǎn)數(shù)量較多時(shí),會(huì)產(chǎn)生一定的性能問(wèn)題

4搁凸、Fiber是什么媚值?有什么用?

在React15版本的時(shí)候护糖,如有組件要更新褥芒,則會(huì)遞歸向下遍歷整個(gè)虛擬DOM樹來(lái)判斷需要更新的地方。這種遞歸的方式弊端在于無(wú)法中斷嫡良,這要會(huì)造成如果我們需要更新一些龐大的組件锰扶,那么更新過(guò)程就會(huì)長(zhǎng)時(shí)間阻塞主線程献酗,從而造成用戶的交互、動(dòng)畫的更新等都不能及時(shí)響應(yīng)坷牛。

React組件更新過(guò)程簡(jiǎn)言之就是在持續(xù)調(diào)用函數(shù)的過(guò)程罕偎,這樣的過(guò)程會(huì)形成一個(gè)虛擬的調(diào)用棧。加入能控制這個(gè)調(diào)用棧的執(zhí)行京闰,把整個(gè)更新任務(wù)拆解開颜及,盡可能將更新任務(wù)放在瀏覽器空閑時(shí)間去執(zhí)行,那么就能解決以上問(wèn)題

Fiber重新實(shí)現(xiàn)了React的核心算法忙干,他有能力將整個(gè)更新任務(wù)拆分為一個(gè)個(gè)小的任務(wù)器予,并且能控制這些任務(wù)的執(zhí)行,主要包括兩個(gè)核心技術(shù):

(1)新的數(shù)據(jù)結(jié)構(gòu)fiber

fiber被認(rèn)為是一個(gè)工作單元捐迫,執(zhí)行更新任務(wù)的整個(gè)流程(不包括渲染)就是在反復(fù)尋找工作單元并運(yùn)行他們乾翔,實(shí)現(xiàn)拆分任務(wù)的功能。拆分成工作單元的目的就是為了能控制stack frame(調(diào)用棧中的內(nèi)容)施戴,可以隨時(shí)隨地執(zhí)行他們反浓,由此使得我們?cè)诿窟\(yùn)行一個(gè)工作單元后都可以按照情況繼續(xù)執(zhí)行或中斷工作(中斷的決定權(quán)在于調(diào)度器)。fiber內(nèi)部存儲(chǔ)了很多上下文信息赞哗,可以把它認(rèn)為是改進(jìn)版的虛擬DOM雷则,同樣也對(duì)應(yīng)了組件實(shí)例及DOM元素。同時(shí)fiber也會(huì)組成fiber tree肪笋,但結(jié)構(gòu)不再是一個(gè)樹形月劈,而是一個(gè)鏈表的結(jié)構(gòu)

```

{

//瀏覽器環(huán)境下指DOM節(jié)點(diǎn)

stateNode: any,

//形成列表結(jié)構(gòu)

return: Fiber | null,

child: Fiber | null,

sibling: Fiber | null,

//更新相關(guān)

pendingProps: any, //新的props

memoizedProps: any, //舊的props

//存儲(chǔ)setState中的第一個(gè)參數(shù)

updateQueue: UpdateQueue?| null,

memoizedState: any, //舊的state

//調(diào)度相關(guān)

expirationTime: ExpirationTime, //任務(wù)過(guò)期時(shí)間

//大部分情況下每個(gè)fiber都有一個(gè)替身fiber

//在更新過(guò)程中藤乙,所有操作都在替身上完成猜揪,當(dāng)渲染完成后,替身會(huì)替代本身

alternate: Fiber | null,

//先簡(jiǎn)單任務(wù)是更新DOM相關(guān)的內(nèi)容

effectTag: SideEffectTag,? //指這個(gè)節(jié)點(diǎn)需要進(jìn)行的DOM操作

//以下三個(gè)屬性也會(huì)形成一個(gè)鏈表

nextEffect: Fiber | null,? //下一個(gè)需要進(jìn)行DOM操作的節(jié)點(diǎn)

firstEffect: Fiber | null,? //第一個(gè)需要進(jìn)行DOM操作的節(jié)點(diǎn)

lastEffect: Fiber | null,? //最后一個(gè)需要進(jìn)行DOM操作的節(jié)點(diǎn)坛梁,同時(shí)也可用于恢復(fù)任務(wù)

}

```

Fiber和fiber不是同一個(gè)概念而姐。前者代表新的調(diào)和器,后者代表fiber node划咐,也可以認(rèn)為是改進(jìn)后的虛擬DOM

(2)調(diào)度器

每次有新的更新任務(wù)發(fā)生的時(shí)候拴念,調(diào)度器都會(huì)按照策略給這些任務(wù)分配一個(gè)優(yōu)先級(jí)。通過(guò)這個(gè)優(yōu)先級(jí)可以獲取一個(gè)該更新任務(wù)必須執(zhí)行的截止時(shí)間褐缠,優(yōu)先級(jí)越高截止時(shí)間就越近政鼠,反之亦然。調(diào)度器通過(guò)實(shí)現(xiàn)requestIdleCallback函數(shù)來(lái)做到在瀏覽器空閑的時(shí)候去執(zhí)行這些更新任務(wù)队魏。簡(jiǎn)單的說(shuō)缔俄,就是通過(guò)定時(shí)器的方式來(lái)獲取每一幀的結(jié)束時(shí)間,得到每一幀的結(jié)束時(shí)間就能判斷當(dāng)下距離結(jié)束時(shí)間的差值。如果還未到結(jié)束時(shí)間俐载,則可以繼續(xù)執(zhí)行更新任務(wù)蟹略,如果已經(jīng)過(guò)了結(jié)束時(shí)間,那么當(dāng)前幀已經(jīng)沒(méi)有時(shí)間執(zhí)行任務(wù)遏佣,必須把執(zhí)行權(quán)交還給瀏覽器锋谐,即打斷任務(wù)的執(zhí)行怒竿。另外當(dāng)開始執(zhí)行更新任務(wù)時(shí),如果有新的更新任務(wù)進(jìn)來(lái),那么調(diào)度器就會(huì)按照兩者的優(yōu)先級(jí)大小來(lái)進(jìn)行決策十电。如果新的任務(wù)優(yōu)先級(jí)小急前,那么繼續(xù)當(dāng)下的任務(wù)鹃祖,如果新的任務(wù)優(yōu)先級(jí)大躏吊,那么會(huì)打斷任務(wù)并開始新的任務(wù)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市稍刀,隨后出現(xiàn)的幾起案子撩独,更是在濱河造成了極大的恐慌,老刑警劉巖账月,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件综膀,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡局齿,警方通過(guò)查閱死者的電腦和手機(jī)剧劝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)抓歼,“玉大人讥此,你說(shuō)我怎么就攤上這事∫テ蓿” “怎么了暂论?”我有些...
    開封第一講書人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)拌禾。 經(jīng)常有香客問(wèn)我,道長(zhǎng)展哭,這世上最難降的妖魔是什么湃窍? 我笑而不...
    開封第一講書人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮匪傍,結(jié)果婚禮上您市,老公的妹妹穿的比我還像新娘。我一直安慰自己役衡,他們只是感情好茵休,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般榕莺。 火紅的嫁衣襯著肌膚如雪俐芯。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,185評(píng)論 1 284
  • 那天钉鸯,我揣著相機(jī)與錄音吧史,去河邊找鬼。 笑死唠雕,一個(gè)胖子當(dāng)著我的面吹牛贸营,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播岩睁,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼钞脂,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了捕儒?” 一聲冷哼從身側(cè)響起冰啃,我...
    開封第一講書人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎肋层,沒(méi)想到半個(gè)月后亿笤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡栋猖,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年净薛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蒲拉。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡肃拜,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出雌团,到底是詐尸還是另有隱情燃领,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布锦援,位于F島的核電站猛蔽,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏灵寺。R本人自食惡果不足惜曼库,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望略板。 院中可真熱鬧毁枯,春花似錦、人聲如沸叮称。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至赂韵,卻和暖如春娱节,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背右锨。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工括堤, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人绍移。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓悄窃,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親蹂窖。 傳聞我的和親對(duì)象是個(gè)殘疾皇子轧抗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容

  • 文章首發(fā)于個(gè)人博客 這是我 Deep In React 系列的第二篇文章,如果還沒(méi)有讀過(guò)的強(qiáng)烈建議你先讀第一篇:詳...
    勿忘巛心安閱讀 1,042評(píng)論 1 2
  • 前言 Facebook 的研發(fā)能力真是驚人瞬测, Fiber 架構(gòu)給 React 帶來(lái)了新視野的同時(shí)横媚,將調(diào)度一詞介紹給...
    Floveluy閱讀 1,754評(píng)論 1 5
  • 背景 前段時(shí)間準(zhǔn)備前端招聘事項(xiàng),復(fù)習(xí)前端React相關(guān)知識(shí)月趟;復(fù)習(xí)React16新的生命周期:棄用了componen...
    蕭強(qiáng)閱讀 2,206評(píng)論 0 2
  • 跟一起包郵的小伙伴約超市灯蝴,按著在濟(jì)南的習(xí)慣一溜一溜的逛,逛到乳制品那圈我發(fā)現(xiàn)今天的冠益乳不論高的矮的都粘了一個(gè)小王...
    遠(yuǎn)山夕顏閱讀 141評(píng)論 0 0
  • 歡迎訪問(wèn)我的博客https://qqqww.com孝宗,祝碼農(nóng)同胞們?cè)缛兆呱先松鷰p峰穷躁,迎娶白富美~~~ 1 圖解Vue...
    這里王工頭閱讀 621評(píng)論 0 0