自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

面試官:“寶子,setState 是同步還是異步的呀?”

開發(fā) 前端
在進(jìn)入主題之前,你肯定需要先學(xué)會(huì) React 的基本使用。如果不會(huì),請(qǐng)點(diǎn)贊離開;如果會(huì)用 React ,那就點(diǎn)贊收藏后離開(●'?'●)。

[[417888]]

本文轉(zhuǎn)載自微信公眾號(hào)「勾勾的前端世界」,作者西嶺。轉(zhuǎn)載本文請(qǐng)聯(lián)系勾勾的前端世界公眾號(hào)。

這一次,我將帶你一次性搞懂 React 中常見(jiàn)的 setState 原理。

setState 本身的默認(rèn)行為

在進(jìn)入主題之前,你肯定需要先學(xué)會(huì) React 的基本使用。如果不會(huì),請(qǐng)點(diǎn)贊離開;如果會(huì)用 React ,那就點(diǎn)贊收藏后離開(●'?'●)。

我們?cè)谑褂?React 的時(shí)候,經(jīng)常會(huì)用到 state(一句廢話),但是真正能完全搞清楚 setState 的帥哥美女,確實(shí)沒(méi)幾個(gè)。畢竟程序員都不太可能像我一樣博學(xué)(和好看)。那么,要搞清楚它,應(yīng)該去投胎(整容)嗎?

不,你需要先搞清楚 setState 本身的默認(rèn)行為。

其實(shí)也很簡(jiǎn)單,我們都知道,setState可以傳遞對(duì)象形式的狀態(tài),也可以傳遞函數(shù)形式的狀態(tài)。而不論狀態(tài)是對(duì)象形式還是函數(shù)形式,它都會(huì)先將所有狀態(tài)保存起來(lái),然后進(jìn)行狀態(tài)合并,所有狀態(tài)合并完成后再進(jìn)行一次性 DOM 更新。

如果狀態(tài)是對(duì)象形式,后面的狀態(tài)會(huì)直接覆蓋前面的狀態(tài)。類似于 Object.assign() 的合并操作。

對(duì)于對(duì)象狀態(tài)這一點(diǎn),我們有請(qǐng)翠花,上代碼:

運(yùn)行代碼,Dom 中展示的結(jié)果為 1。很顯然兩次 setState 只有一次生效了。

真的嗎?其實(shí)兩次都有生效,只不過(guò)這兩次 setState 在執(zhí)行前,被合并成了一個(gè)。你不能說(shuō)到底是那個(gè)生效,你可以說(shuō)兩個(gè)都沒(méi)生效,因?yàn)樽罱K執(zhí)行的是被合并的那個(gè)代碼。

如果狀態(tài)是函數(shù)形式,那么依次調(diào)用函數(shù)進(jìn)行狀態(tài)累積,所有函數(shù)調(diào)用完成后, 得到最終狀態(tài),最終進(jìn)行一次性 DOM 更新。

翠花,再來(lái)一段代碼……

明顯不一樣的結(jié)果就能說(shuō)明,兩次都執(zhí)行了,因?yàn)楹瘮?shù)狀態(tài)并不會(huì)合并,而是以此運(yùn)行。

好了,翠花可以先下去休息了,前置只是我們已經(jīng)梳理完了,那么,對(duì)于 setState 的研究就結(jié)束了嗎?當(dāng)然不是,接下來(lái),讓我們換個(gè)場(chǎng)子,繼續(xù)掰滔(battle)。

setState 同步 OR 異步

在面試場(chǎng)景中,只要和 React 相關(guān),面試官一定舔著臉問(wèn)你:“ 寶子,setState 是同步還是異步的呀 ” 。

面對(duì)這樣的無(wú)恥刁難,我們需要先明確,從 API 層面上說(shuō),它就是普通的調(diào)用執(zhí)行的函數(shù),自然是同步 API 。

因此,這里所說(shuō)的同步和異步指的是 API 調(diào)用后更新 DOM 是同步還是異步的。

來(lái),我們有請(qǐng)娜塔莎,上代碼……

果然,洋妹子端上來(lái)的代碼確實(shí)不好消化,通過(guò)結(jié)果我們發(fā)現(xiàn),非常奇怪的一個(gè)現(xiàn)象:

第一次事件執(zhí)行顯然為異步的,先打印了兩個(gè) 0,Dom 隨之改變?yōu)?1 ;

第二次同樣是異步的,但是我們發(fā)現(xiàn)多次執(zhí)行沒(méi)效果 (異步?);

而第三次又是同步執(zhí)行的了;

這什么情況,洋妹子給我們下了迷藥嗎?看我葵花寶典戳破它。

先說(shuō)結(jié)論,首先,同步和異步主要取決于它被調(diào)用的環(huán)境。

  • 如果 setState 在 React 能夠控制的范圍被調(diào)用,它就是異步的。

比如合成事件處理函數(shù), 生命周期函數(shù), 此時(shí)會(huì)進(jìn)行批量更新, 也就是將狀態(tài)合并后再進(jìn)行 DOM 更新。

  • 如果 setState 在原生 JavaScript 控制的范圍被調(diào)用,它就是同步的。

比如原生事件處理函數(shù)中, 定時(shí)器回調(diào)函數(shù)中, Ajax 回調(diào)函數(shù)中, 此時(shí) setState 被調(diào)用后會(huì)立即更新 DOM 。

為什么會(huì)這樣呢?

其實(shí),我們看到的所謂的 “異步”,是開啟了 “批量更新” 模式的。

批量更新模式可以減少真實(shí) DOM 渲染的次數(shù),所以只要是 React 能夠控制的范圍,出于性能因素考慮,一定是批量更新模式。批量更新會(huì)先合并狀態(tài),再一次性做 DOM 更新。

那么假設(shè)沒(méi)有批量更新呢?

從生命周期的角度來(lái)看,每一次的 setState 都是一個(gè)完整的更新流程,這里面就包含了重新渲染 (re-render) 在內(nèi)的很多操作,大體的流程如下:

  1. shouldComponentUpdate->componentWillUpdate->render->componentDidUpdate; 

re-render 本身涉及對(duì) DOM 的操作,它會(huì)帶來(lái)較大的性能開銷。假如說(shuō) “一次 setState 就觸發(fā)一個(gè)完整的更新流程” 這個(gè)結(jié)論成立,那么每一次 setState的調(diào)用都會(huì)觸發(fā)一次 re-render,我們的視圖很可能沒(méi)刷新幾次就卡死了,渲染就會(huì)出現(xiàn)下面這樣的流程:

因此,setState 異步(或者說(shuō)是批量更新)的一個(gè)重要?jiǎng)訖C(jī)就是避免頻繁的 re-render。

在實(shí)際的 React 運(yùn)行時(shí)中,setState 異步的實(shí)現(xiàn)方式有點(diǎn)類似于瀏覽器里的 Event-Loop:

每來(lái)一個(gè)setState,就把它塞進(jìn)一個(gè)隊(duì)列里。等時(shí)機(jī)成熟,再把隊(duì)列里的 state 結(jié)果做合并,最后只針對(duì)最新的 state 值走一次更新流程。

這個(gè)過(guò)程,叫作“批量更新”,批量更新的過(guò)程正如下面代碼中的箭頭流程圖所示:

只要我們的同步代碼還在執(zhí)行,“進(jìn)隊(duì)列” 這個(gè)動(dòng)作就不會(huì)停止。因此就算我們?cè)赗eact 中寫了一個(gè) N 次的 setState 循環(huán),也只是會(huì)增加 state 任務(wù)入隊(duì)的次數(shù),并不會(huì)帶來(lái)頻繁的 re-render。當(dāng) N 次調(diào)用結(jié)束后,僅僅是 state 的任務(wù)隊(duì)列內(nèi)容發(fā)生了變化, state 本身并不會(huì)立刻改變。

為了更好地讓你吃下娜塔莎,哦不對(duì),是娜塔莎端上來(lái)的美食,我?guī)湍闶崂砹?setState 的執(zhí)行流程圖:

 

當(dāng)然,你可能看不懂這個(gè)流程圖(是有多笨啊),沒(méi)關(guān)系,下面還會(huì)有的。

如果為非批量更新模式,調(diào)用多少次 setState 就會(huì)渲染多少次真實(shí) DOM,性能較低。

但是我們?cè)谀承l件下需要對(duì) JS 控制的區(qū)域?qū)崿F(xiàn)批量更新 ( 異步更新 DOM ) ,那應(yīng)該怎么做呢?

強(qiáng)制批量更新

其實(shí)很簡(jiǎn)單,我都不好意思說(shuō) so easy ,因?yàn)檫@玩意簡(jiǎn)直就是 so TM 的 easy 。

我們只需要將代碼包裹在 unstable_batchedUpdates 方法的回調(diào)函數(shù)中就可以實(shí)現(xiàn)強(qiáng)制批量更新。

具體使用方式也很簡(jiǎn)單,從 react-dom 中引入進(jìn)來(lái),然后將代碼放入調(diào)用函數(shù)中就可以了。

(翠花和娜塔莎結(jié)婚了,我來(lái)給大家上代碼)

 

截止到現(xiàn)在,我們成就了一對(duì)完美的愛(ài)情,啊,呸~

 

責(zé)任編輯:武曉燕 來(lái)源: 勾勾的前端世界
相關(guān)推薦

2022-06-13 06:20:42

setStatereact18

2021-06-29 09:47:34

ReactSetState機(jī)制

2023-11-15 09:14:27

Java值傳遞

2021-09-07 10:44:33

Java 注解開發(fā)

2024-10-24 09:22:30

2021-02-19 10:02:57

HTTPSJava安全

2024-02-04 10:08:34

2024-12-25 15:44:15

2021-12-08 06:53:29

面試動(dòng)態(tài)代理

2024-02-22 15:36:23

Java內(nèi)存模型線程

2024-05-11 15:11:44

系統(tǒng)軟件部署

2022-09-29 07:30:57

數(shù)據(jù)庫(kù)索引字段

2015-08-13 10:29:12

面試面試官

2020-08-10 07:58:18

異步編程調(diào)用

2022-07-15 08:22:42

對(duì)象符串鍵Symbol

2023-02-08 07:04:20

死鎖面試官單元

2025-04-14 11:41:12

RocketMQ長(zhǎng)輪詢配置

2024-10-15 10:00:06

2021-04-30 20:25:20

Spring MVCJava代碼

2021-03-03 17:26:45

面試Synchronous底層
點(diǎn)贊
收藏

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