精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

React 的 SetState 是同步還是異步?

開發(fā) 前端
setState 是同步還是異步這個(gè)問題等 react18 普及以后就不會(huì)再有了,因?yàn)樗械?setState 都是異步批量執(zhí)行了。

setState 是同步還是異步?

肯定是異步的呀。

確定么?那看一下這段代碼會(huì)打印什么:

import { Component } from 'react';
class Dong extends Component {
constructor() {
super();
this.state = {
count: 0
}
}
componentDidMount() {
setTimeout(() => {
this.setState({
count: 1
});
console.log(this.state.count);
this.setState({
count: 2
});
console.log(this.state.count);
});
}
render() {
console.log('render:', this.state.count);
return <div>{this.state.count}</div>;
}
}

在 setTimeout 里修改了兩次 state,并打印了 state 的值。

如果是異步的,那應(yīng)該打印的時(shí)候 count 還沒修改,依然是 0,所以打印兩次 0。

然后初始化渲染一次,setState 后再渲染一次,應(yīng)該 render 兩次,count 分別為 0 和 2。

按照異步的方式來分析,確實(shí)應(yīng)該是這樣的。

我們執(zhí)行一下:

圖片

會(huì)發(fā)現(xiàn)兩次打印分別是 1 和 2,也就是說 setState 同步修改了 state,然后每次都觸發(fā)了渲染,所以一共 render 3 次,分別是 0、1、2。

那這么說 setState 是同步的?

確定么?那看下這段代碼會(huì)打印什么?

class Dong extends Component {
constructor() {
super();
this.state = {
count: 0
}
}
componentDidMount() {
this.setState({
count: 1
});
console.log(this.state.count);
this.setState({
count: 2
});
console.log(this.state.count);
this.setState({
count: 3
});
console.log(this.state.count);
}
render() {
console.log('render:', this.state.count);
return <div>{this.state.count}</div>;
}
}

如果 setState 是同步的,那執(zhí)行完就會(huì)修改 state,應(yīng)該分別打印 1、2、3,然后觸發(fā)三次 render,加上最開始的一次,一共四次,打印 0、1、2、3。

我們來執(zhí)行一下:

圖片

三次打印都是 0,這說明 setState 是異步的。而且三次 setState 只觸發(fā)了一次 render,加上最開始的 render,一共兩次,打印 0、3。

什么鬼,怎么又是異步的了?

而且不止 class 組件的 setState 是這樣,換成 function 組件的 useState 也是一樣的:

比如修改三次 state,只會(huì) render 一次:

圖片

而在 setTimeout 里,每次修改 state 都會(huì) render:

圖片

是不是有點(diǎn)暈,什么情況下 setState 是同步的,什么情況下是異步的呢?

這要從源碼找答案了,我們來讀一下 setState 的源碼。

首先理一下 React 渲染的流程:

React 渲染流程

react 通過 jsx 來描述界面,jsx 可以通過 babel 等編譯器編譯成 render function,然后執(zhí)行后產(chǎn)生 vdom:

圖片

這個(gè) vdom 也不是直接渲染的,而是會(huì)先轉(zhuǎn)化為 fiber,之后再渲染。

因?yàn)?vdom 里每個(gè)節(jié)點(diǎn)只記錄了子節(jié)點(diǎn)(children),沒有記錄兄弟節(jié)點(diǎn),所以必須一次性渲染完,不能打斷。

而轉(zhuǎn)成 fiber 的鏈表結(jié)構(gòu)就會(huì)記錄父節(jié)點(diǎn)(return)、子節(jié)點(diǎn)(child)、兄弟節(jié)點(diǎn)(sibling),就變成了可打斷的。

圖片

這里的 vdom 是 React Element 對(duì)象:

圖片

轉(zhuǎn)化為 fiber 之后是 FiberNode 的對(duì)象:

圖片

從 vdom 轉(zhuǎn)換成 fiber 的過程就叫做 reconcile,轉(zhuǎn)換過程中會(huì)順便創(chuàng)建對(duì)應(yīng)的 dom 元素,然后全部轉(zhuǎn)換完后一次性 commit 到 dom。

這個(gè)過程不是一次性的,是通過 scheduler 調(diào)度執(zhí)行的,那也就可以分批次進(jìn)行,也就是可打斷的含義。

這就是 React 的 fiber 架構(gòu)下的渲染流程。

理論說完了,我們來對(duì)應(yīng)到源碼看一下(這里看的是 v17 的源碼):

react 把 schedule 和 reconcile 叫做 render 階段,這個(gè)階段就是把 vdom 轉(zhuǎn)為 fiber。(schedule 只是讓 reconcile 可以分多次執(zhí)行,可以打斷,但做的事情是不變的,所以 schedule 也是 render 階段的一部分)。

之后把 fiber 更新到 dom 的過程就叫做 commit 階段。

對(duì)應(yīng)到源碼里就是這樣的:

圖片

這個(gè) performSyncWorkOnRoot 就是渲染的入口,就像之前所說的,會(huì)先執(zhí)行 render 階段,把 vdom 轉(zhuǎn)成 fbier,然后再執(zhí)行 commit,更新到 dom。

render 階段會(huì)執(zhí)行一個(gè)調(diào)度的 loop:

圖片

這個(gè) loop 就是不斷地處理一個(gè)個(gè) fiber 的 reconcile:

圖片

每個(gè)節(jié)點(diǎn)都有 beginWork 和 completeWork 兩個(gè)階段,因?yàn)橐?vdom 轉(zhuǎn) fiber,而 vdom 是一個(gè)樹形結(jié)構(gòu),需要遞歸處理:

圖片

具體不同節(jié)點(diǎn)的 reconcile 邏輯不同:

圖片

比如函數(shù)組件會(huì)被調(diào)用,拿到 render 出的 vdom 繼續(xù)進(jìn)行 reconcile:

圖片

比如 class 組件會(huì)創(chuàng)建實(shí)例,調(diào)用 render 方法,拿到 vdom,然后再繼續(xù) renconcileChildren。

圖片

總之,vdom 轉(zhuǎn) fiber 是一個(gè)遞歸進(jìn)行的過程。

之后再進(jìn)行 commit 階段。

整個(gè)渲染流程的入口就是 performSyncWorkOnRoot 函數(shù)。

渲染的流程講完了,接下來就是 setState 怎么觸發(fā)渲染的流程了:

setState 的流程

我們知道了渲染的入口就是 performSyncWorkOnRoot 函數(shù),那 setState 修改完?duì)顟B(tài),觸發(fā)一下這個(gè)函數(shù)不就行了?

確實(shí)是這樣的。setState 會(huì)調(diào)用 dispathAction,創(chuàng)建一個(gè) update 對(duì)象放到 fiber 節(jié)點(diǎn)的 updateQueue 上,然后調(diào)度渲染:

圖片

調(diào)度更新自然就是調(diào)度上面說的那個(gè) performSyncWorkOnRoot 函數(shù):

react 會(huì)先從觸發(fā) update 的 fiber 往上找到根 fiber 節(jié)點(diǎn),然后再調(diào)用 performSyncWorkOnRoot 的函數(shù)進(jìn)行渲染:

圖片

這就是 setState 之后觸發(fā)重新渲染的實(shí)現(xiàn)。

而 setState 是同步還是異步,也就是在這一段控制的。

我們看到判斷條件里有個(gè) excutionContext,這個(gè)是用來標(biāo)識(shí)當(dāng)前環(huán)境的,比如是批量還是非批量,是否執(zhí)行過 render 階段、commit 階段。

其實(shí)在 ReactDOM.render 執(zhí)行的時(shí)候會(huì)先調(diào)用 unbatchUpdates 函數(shù):

圖片

這個(gè)函數(shù)會(huì)在 excutionContext 中設(shè)置一個(gè) unbatach 的 flag:

圖片

這樣在 update 的時(shí)候,就會(huì)立刻執(zhí)行 performSyncWorkOnRoot 來渲染。因?yàn)槭状武秩镜臅r(shí)候是馬上就要渲染的,沒必要調(diào)度。

圖片

之后走到 commit 階段會(huì)設(shè)置一個(gè) commit 的 flag:

圖片

然后再次 setState 就不會(huì)走到 unbatch 的分支了。

那為什么 setTimeout 里面的 setState 會(huì)同步執(zhí)行呢?

因?yàn)橹苯訌?setTimeout 執(zhí)行的異步代碼是沒有設(shè)置 excutionContext 的,那就會(huì)走到 NoContext 的分支,會(huì)立刻渲染。(這里的 flush 最終會(huì)調(diào)用 performSyncWorkOnRoot 函數(shù)來渲染):

圖片

有什么辦法能讓 setTimeout 里執(zhí)行的函數(shù)也有 excutionContext 呢?

其實(shí) react17 暴露了 batchUpdates 的 api,用它包裹下,里面的 setState 就會(huì)批量執(zhí)行了:

圖片

它的源碼其實(shí)就是設(shè)置了下 excutionContext:

圖片

這樣等 setState 全部執(zhí)行完之后再 flush,調(diào)用 peformSyncWorkOnRoot 渲染,效果就是批量的 setState 了。

其實(shí)按理來說 setState 不能叫異步,還是在同一個(gè)調(diào)用棧執(zhí)行的,只不過順序不同而已。只能叫批量還是非批量。

在 react17 中是這么處理的,如果是 react18,使用 createRoot 的 api 的話,就不會(huì)有這種問題了,就算是 setTimeout 里的代碼也能批量執(zhí)行,

圖片

而且為了兼容 react17 這種情況,還做了特殊處理,當(dāng)沒有開啟并發(fā)模式,也就是還是用 ReactDOM.render 的 api 時(shí),沒有指定 excutionContext 還會(huì)立刻渲染:

圖片

等 react 18 普及以后,所有的 setState 都是批量的了,就不會(huì)再有批量還是非批量的問題。

總結(jié)

雖然我們討論的是 setState 的同步異步,但這個(gè)不是 setTimeout、Promise 那種異步,只是指 setState 之后是否 state 馬上變了,是否馬上 render。

我們梳理了下 React 的渲染流程,包括 render 階段、commit 階段,render 階段是從 vdom 轉(zhuǎn) fiber,包含 schedule 和 reconcile,commit 階段是把 fiber 更新到 dom。渲染流程的入口是 performSyncWorkOnRoot 函數(shù)。

setState 會(huì)創(chuàng)建 update 對(duì)象掛到 fiber 對(duì)象上,然后調(diào)度 performSyncWorkOnRoot 重新渲染。

在 react17 中,setState 是批量執(zhí)行的,因?yàn)閳?zhí)行前會(huì)設(shè)置 executionContext。但如果在 setTimeout、事件監(jiān)聽器等函數(shù)里,就不會(huì)設(shè)置 executionContext 了,這時(shí)候 setState 會(huì)同步執(zhí)行。可以在外面包一層 batchUpdates 函數(shù),手動(dòng)設(shè)置下 excutionContext 來切換成異步批量執(zhí)行。

在 react18 里面,如果用 createRoot 的 api,就不會(huì)有這種問題了。

setState 是同步還是異步這個(gè)問題等 react18 普及以后就不會(huì)再有了,因?yàn)樗械?setState 都是異步批量執(zhí)行了。

責(zé)任編輯:姜華 來源: 神光的編程秘籍
相關(guān)推薦

2021-08-16 18:52:09

同步異步React

2017-04-12 11:15:52

ReactsetState策略

2021-08-03 07:40:47

宏任務(wù)微任務(wù)React

2020-09-24 08:45:10

React架構(gòu)源碼

2024-06-07 07:56:35

2023-09-07 08:15:58

場(chǎng)景同步異步

2021-06-29 09:47:34

ReactSetState機(jī)制

2018-01-30 18:15:12

Python網(wǎng)絡(luò)爬蟲gevent

2023-03-13 17:18:09

OkHttp同步異步

2021-06-07 08:41:59

React異步組件

2021-09-08 18:42:29

setStateAPI函數(shù)

2025-10-15 02:11:00

2024-07-26 21:55:39

RustRESTfulAPI

2013-03-08 09:33:25

JavaScript同步異步

2025-06-30 00:01:00

Node.js?Go線程

2023-05-31 07:29:46

2020-10-12 17:33:32

JavaScript框架技術(shù)

2020-09-25 18:10:06

Python 開發(fā)編程語(yǔ)言

2024-10-09 11:31:51

2024-07-11 16:49:43

同步通信異步通信通信
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

国产精品青青草| 亚洲第一精品自拍| 亚洲一区二区三区午夜| 99热这里只有精品在线| 日韩午夜av在线| 亚洲色图欧美制服丝袜另类第一页| 中文字幕永久视频| caoporn免费在线视频| 成人免费av资源| 日本久久久久亚洲中字幕| 免费精品在线视频| 欧美电影完整版在线观看| 欧美三电影在线| 九一国产精品视频| 日本高清中文字幕在线| 99麻豆久久久国产精品免费 | 欧美精品aⅴ在线视频| 激情成人开心网| 国产视频精品久久| 国产成人精品亚洲日本在线桃色| 日本午夜精品理论片a级appf发布| 国产精品一区二区亚洲| 日韩精品免费一区二区夜夜嗨 | 刘玥91精选国产在线观看| 日韩中文字幕区一区有砖一区 | 欧美三区四区| 亚洲成av人片| 亚洲精品天堂成人片av在线播放| 可以在线观看的黄色| 福利电影一区二区三区| 国产精品视频永久免费播放| 日韩欧美亚洲一区二区三区| 欧美一区影院| 综合国产在线观看| 丰满少妇高潮一区二区| 国产另类在线| 欧美变态口味重另类| 亚洲一区日韩精品| 欧洲精品一区二区三区| 一本久久a久久精品亚洲| 日韩精品一区二区在线视频 | 日韩 国产 欧美| 一本久道久久综合婷婷鲸鱼| 欧美激情欧美激情| 精品自拍偷拍视频| 首页国产精品| 中文字幕久热精品在线视频| www.久久国产| 青草久久视频| 亚洲精品av在线| 精品人妻在线视频| 超碰成人在线免费| 精品国产乱码久久久久久蜜臀 | 国产va亚洲va在线va| a级影片在线观看| 亚洲人被黑人高潮完整版| 亚洲国产日韩av| 国产成人在线亚洲欧美| 欧美一区二区激情视频| 国产欧美日韩一区二区三区在线| 高清欧美一区二区三区| 日本一本高清视频| 亚洲人体偷拍| 456国产精品| 亚洲另类在线观看| 日日骚欧美日韩| 国产精品国模在线| 伊人免费在线观看高清版| 另类的小说在线视频另类成人小视频在线 | www.av在线播放| 亚洲国产精品ⅴa在线观看| 日韩在线导航| 在线看黄色av| 亚洲免费在线视频| 成人小视频在线观看免费| 国产丝袜精品丝袜| 欧美性色视频在线| 能看的毛片网站| 日本中文字幕视频一区| 欧美一区二区福利在线| 中文字幕在线观看91| 久久九九热re6这里有精品| 亚洲成人性视频| 亚洲综合色一区| 免费一区二区| 日韩一区在线视频| 久久精品99国产精| 亚洲视频1区| 国产精品视频导航| 国产精品系列视频| 成人精品gif动图一区| 国产一区二区三区日韩| 中文字幕亚洲欧美日韩2019| 精品无码久久久久成人漫画| 91久久视频| 国产精品99导航| 国产欧美日韩综合精品一区二区三区| 国产盗摄一区二区三区| 久久综合毛片| 老司机av在线免费看| 亚洲高清免费观看| 日本成人黄色网| 日韩欧美中文字幕在线视频 | 五月婷婷久久综合| 五月天婷婷激情视频| 亚洲天堂av资源在线观看| 亚洲性视频网站| 欧美成人片在线观看| 久久中文在线| 欧美日韩精品二区第二页| 波多野结衣精品久久| 牛牛澡牛牛爽一区二区| 亚洲欧洲综合另类在线| 欧美aⅴ在线观看| 日韩高清一区| 中文字幕在线成人| 日本一区二区在线视频| 九色网友自拍视频手机在线| 尤物视频一区二区| 天天爽人人爽夜夜爽| 国产精东传媒成人av电影| 国产亚洲一区二区精品| 日韩特黄一级片| 国产精品一区在线| 深田咏美在线x99av| 看黄在线观看| 精品美女被调教视频大全网站| 国产精品久久久视频| 国产一区二区三区久久久久久久久| 91免费在线视频| 91在线直播| 在线视频欧美精品| av无码av天天av天天爽| 好看的亚洲午夜视频在线| 成人高清视频观看www| 福利小视频在线观看| 天天操天天干天天综合网| 无码人妻一区二区三区精品视频 | 成人一道本在线| 杨幂一区欧美专区| 51一区二区三区| 亚洲精选中文字幕| 日韩久久久久久久久| 国产福利91精品一区| 美女黄色片网站| 亚洲91在线| 色偷偷av一区二区三区| 国产女优在线播放| 欧美国产日本韩| 高清一区二区视频| 色婷婷综合网| 国产日韩av在线播放| 在线激情小视频| 欧美三级三级三级| 成人欧美一区二区三区黑人一| 日本美女一区二区三区| 视频一区视频二区视频| 精品无人乱码一区二区三区| 国产一区二区日韩| 正在播放木下凛凛xv99| 国产精品美女久久久久aⅴ国产馆| 冲田杏梨av在线| 欧美mv日韩| 91午夜在线播放| 日本动漫理论片在线观看网站 | 欧美日韩中文字幕在线观看| 久久99久久久久久久久久久| 中文字幕一区二区三区有限公司| 91麻豆精品| 欧美贵妇videos办公室| 黄色福利在线观看| 欧美日韩午夜剧场| 亚洲国产日韩一区无码精品久久久| 日韩在线a电影| 夜夜爽www精品| 欧美精品三级在线| 精品久久久久久久久久久久久久久久久| 欧美另类一区| av资源一区| 日韩麻豆第一页| 国产情侣免费视频| ●精品国产综合乱码久久久久| 粗大的内捧猛烈进出视频| 亚洲精品色图| 日产国产精品精品a∨| 日韩久久一区| 欧美精品成人91久久久久久久| 亚洲色图 校园春色| 欧美三级三级三级爽爽爽| 国产1区2区3区4区| 91碰在线视频| 成人在线激情视频| 精品在线播放视频| 久久婷婷色综合| www.污网站| 国产日韩综合| 在线天堂一区av电影| 凹凸av导航大全精品| 国产精品久久一| 欧洲一区二区三区| 国产一区二区久久精品| 亚洲成人一级片| 欧美伊人久久久久久久久影院 | 精品99999| 日韩av加勒比| 国产精品久久久久毛片大屁完整版| 日本最新一区二区三区视频观看| 午夜视频在线观看精品中文| 国产精品91在线| 国产亚av手机在线观看| 在线观看亚洲精品| 青草青青在线视频| 精品中文一区| 99视频网站| 亚洲资源在线| 亚洲精品a级片| 亚洲自拍在线观看| 怡红院成人在线| 欧美激情va永久在线播放| 触手亚洲一区二区三区| 亚洲国产高清高潮精品美女| 国产又粗又猛又色又| 欧美日韩一区二区三区在线免费观看 | 国产一区二区三区在线视频| 黄频在线免费观看| 91精品国产色综合久久不卡电影 | 国产精品蜜月aⅴ在线| 国外成人性视频| 成人免费视屏| 中文字幕一区电影| 国产视频三级在线观看播放| 亚洲精品国产品国语在线| www.com在线观看| 欧美丰满少妇xxxbbb| 中文字幕免费视频观看| 日韩欧美国产高清91| y111111国产精品久久婷婷| 在线中文字幕电影| 日韩视频在线一区| av电影在线播放高清免费观看| 亚洲美女性视频| 三级在线播放| 亚洲精品一二区| 日本中文字幕一区二区有码在线| 欧美精品一区二区精品网| 国产成人三级在线播放| 欧美电影在线免费观看| 91精品视频免费在线观看 | 国产极品粉嫩福利姬萌白酱 | 欧美视频完全免费看| 久久99国产综合精品免费| 婷婷丁香激情综合| 日韩av无码中文字幕| 亚洲mv在线观看| 一级片免费网址| 五月天一区二区三区| 一区二区精品在线| 久久久91麻豆精品国产一区| 成人网在线免费看| 99久久久国产| 亚洲aⅴ日韩av电影在线观看 | 国内精品不卡| 精品国产自在精品国产浪潮| 日本最新在线视频| 日韩最新在线视频| av毛片在线看| 九九热这里只有精品6| 另类视频在线| 69久久夜色精品国产69| 国模套图日韩精品一区二区| 国产精品极品在线| www一区二区三区| 91一区二区三区| 国产精品极品| 欧美亚洲第一页| 久久黄色小视频| 国产精品麻豆欧美日韩ww| 国产午夜精品理论片在线| 亚洲一区二区三区四区在线 | 深夜国产在线播放| 欧美激情国产精品| 天堂√中文最新版在线| 国产精品高清在线观看| 国产精品久久久久久久久久辛辛| 成人欧美一区二区三区视频| 香蕉久久99| 中文精品一区二区三区| 亚洲国产午夜| 日韩免费高清在线| 国产综合久久久久久鬼色 | 欧美性猛交丰臀xxxxx网站| 久久久久久蜜桃一区二区| 视频一区视频二区中文| 欧美日韩一区二区三区69堂| 国产福利不卡视频| 最近中文字幕在线mv视频在线| 国产精品国产三级国产aⅴ中文| 久草免费新视频| 欧美性生交xxxxxdddd| 国产精品久久影视| 亚洲福利在线观看| 欧美边添边摸边做边爱免费| 色综合91久久精品中文字幕| 日韩精品99| 超碰国产精品久久国产精品99| 牲欧美videos精品| 亚洲天堂第一区| 老司机久久99久久精品播放免费| 视频区 图片区 小说区| 久久久99精品久久| 久久久久免费看| 欧美日韩不卡在线| 视频午夜在线| 欧美精品videosex性欧美| 国模私拍国内精品国内av| 精品亚洲欧美日韩| 中文字幕免费一区二区三区| 蜜桃免费在线视频| 99re在线视频这里只有精品| 在线看的片片片免费| 欧美影院一区二区三区| 特黄视频在线观看| 九色精品免费永久在线| 天天综合91| 日韩久久在线| 免费在线亚洲欧美| 波多野结衣影院| 欧美色女视频| 91精品国产91久久久久青草| 欧美先锋资源| 欧美日韩在线不卡视频| 国产99久久久久久免费看农村| 国产福利在线导航| 欧洲精品在线观看| 黄色小视频在线观看| 91po在线观看91精品国产性色| 午夜久久av| 欧美黄色免费网址| 国产精品一区二区在线观看网站| 亚洲色图100p| 欧美日韩国产综合久久| 国产三区四区在线观看| 欧美专区在线播放| 狼人精品一区二区三区在线| 国内精品视频一区二区三区| 粉嫩av一区二区三区| 久久精品第一页| 日韩亚洲欧美高清| 人人超在线公开视频| 国产精品免费一区二区| 亚洲一级黄色| 无码人妻精品一区二区三区99不卡| 亚洲午夜精品在线| 欧美熟妇另类久久久久久不卡| 久久久久久久爱| 精品三级av| 青青视频在线播放| 久久久91精品国产一区二区三区| 无码人妻丰满熟妇区五十路| 亚洲性生活视频在线观看| 69堂精品视频在线播放| 中国一区二区三区| 国产成a人无v码亚洲福利| 久久影院一区二区| 亚洲精美色品网站| 日本久久免费| 亚洲成色www久久网站| 激情综合色综合久久| 成人免费毛片东京热| 精品国产乱码久久久久久牛牛| 成入视频在线观看| 欧美第一黄网| 老司机午夜精品99久久| 青青草手机视频在线观看| 精品国产伦一区二区三区免费| av资源亚洲| 正在播放一区| 成人18精品视频| 国产乱码在线观看| 久久视频在线播放| 久久97精品| 午夜免费一区二区| 亚洲精选一二三| 少妇性bbb搡bbb爽爽爽欧美| 国产精品福利观看| 欧美日韩少妇| 91成人破解版| 91精品福利在线一区二区三区 | 91精品国产九九九久久久亚洲| 九九热精品视频在线观看| 亚洲综合婷婷久久| 亚洲成人免费在线| 国产h视频在线观看| 91在线精品观看| 天堂成人免费av电影一区| www色aa色aawww| 亚洲精品视频久久| 久久九九精品视频| 日本美女高潮视频| 亚洲一区免费观看|