成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

React 中 setState 是一個宏任務還是微任務?

開發 前端
Concurrent 模式是一組 React 的新功能,可幫助應用保持響應,并根據用戶的設備性能和網速進行適當的調整。在 Concurrent 模式中,渲染不是阻塞的。

[[414970]]

最近有個朋友面試,面試官問了個奇葩的問題,也就是我寫在標題上的這個問題。

能問出這個問題,面試官應該對 React 不是很了解,也是可能是看到面試者簡歷里面有寫過自己熟悉 React,面試官想通過這個問題來判斷面試者是不是真的熟悉 React ??。

面試官的問法是否正確?

面試官的問題是,setState 是一個宏認為還是微任務,那么在他的認知里,setState 肯定是一個異步操作。為了判斷 setState 到底是不是異步操作,可以先做一個實驗,通過 CRA 新建一個 React 項目,在項目中,編輯如下代碼:

  1. import React from 'react'
  2. import logo from './logo.svg'
  3. import './App.css'
  4.  
  5. class App extends React.Component { 
  6.   state = { 
  7.     count: 1000 
  8.   } 
  9.   render() { 
  10.     return ( 
  11.       <div className="App"
  12.         <img 
  13.           src={logo} alt="logo" 
  14.           className="App-logo" 
  15.           onClick={this.handleClick} 
  16.         /> 
  17.         <p>我的關注人數:{this.state.count}</p> 
  18.       </div> 
  19.     ); 
  20.   } 
  21.  
  22. export default App; 

頁面大概長這樣:

上面的 React Logo 綁定了一個點擊事件,現在需要實現這個點擊事件,在點擊 Logo 之后,進行一次 setState 操作,在 set 操作完成時打印一個 log,并且在 set 操作之前,分別添加一個宏任務和微任務。代碼如下:

  1. handleClick = () => { 
  2.   const fans = Math.floor(Math.random() * 10) 
  3.   setTimeout(() => { 
  4.     console.log('宏任務觸發'
  5.   }) 
  6.   Promise.resolve().then(() => { 
  7.     console.log('微任務觸發'
  8.   }) 
  9.   this.setState({ 
  10.     count: this.state.count + fans 
  11.   }, () => { 
  12.     console.log('新增粉絲數:', fans) 
  13.   }) 

很明顯,在點擊 Logo 之后,先完成了 setState 操作,然后再是微任務的觸發和宏任務的觸發。所以,setState 的執行時機是早于微任務與宏任務的,即使這樣也只能說它的執行時機早于 Promise.then,還不能證明它就是同步任務。

  1. handleClick = () => { 
  2.   const fans = Math.floor(Math.random() * 10) 
  3.   console.log('開始運行'
  4.   this.setState({ 
  5.     count: this.state.count + fans 
  6.   }, () => { 
  7.     console.log('新增粉絲數:', fans) 
  8.   }) 
  9.   console.log('結束運行'

這么看,似乎 setState 又是一個異步的操作。主要原因是,在 React 的生命周期以及綁定的事件流中,所有的 setState 操作會先緩存到一個隊列中,在整個事件結束后或者 mount 流程結束后,才會取出之前緩存的 setState 隊列進行一次計算,觸發 state 更新。只要我們跳出 React 的事件流或者生命周期,就能打破 React 對 setState 的掌控。最簡單的方法,就是把 setState 放到 setTimeout 的匿名函數中。

  1. handleClick = () => { 
  2.   setTimeout(() => { 
  3.     const fans = Math.floor(Math.random() * 10) 
  4.     console.log('開始運行'
  5.     this.setState({ 
  6.       count: this.state.count + fans 
  7.     }, () => { 
  8.       console.log('新增粉絲數:', fans) 
  9.     }) 
  10.     console.log('結束運行'
  11.   }) 

所以,setState 就是一次同步行為,根本不存在面試官的問題。

React 是如何控制 setState 的 ?

前面的案例中,setState 只有在 setTimeout 中才會變得像一個同步方法,這是怎么做到的?

  1. handleClick = () => { 
  2.   // 正常的操作 
  3.   this.setState({ 
  4.     count: this.state.count + 1 
  5.   }) 
  6. handleClick = () => { 
  7.   // 脫離 React 控制的操作 
  8.   setTimeout(() => { 
  9.     this.setState({ 
  10.       count: this.state.count + fans 
  11.     }) 
  12.   }) 

先回顧之前的代碼,在這兩個操作中,我們分別在 Performance 中記錄一次調用棧,看看兩者的調用棧有何區別。

正常操作

脫離 React 控制的操作

在調用棧中,可以看到 Component.setState 方法最終會調用 enqueueSetState 方法,而 enqueueSetState 方法內部會調用 scheduleUpdateOnFiber 方法,區別就在于正常調用的時候,scheduleUpdateOnFiber 方法內只會調用 ensureRootIsScheduled ,在事件方法結束后,才會調用 flushSyncCallbackQueue 方法。而脫離 React 事件流的時候,scheduleUpdateOnFiber 在 ensureRootIsScheduled 調用結束后,會直接調用 flushSyncCallbackQueue 方法,這個方法就是用來更新 state 并重新進行 render 。

  1. function scheduleUpdateOnFiber(fiber, lane, eventTime) { 
  2.   if (lane === SyncLane) { 
  3.     // 同步操作 
  4.     ensureRootIsScheduled(root, eventTime); 
  5.     // 判斷當前是否還在 React 事件流中 
  6.     // 如果不在,直接調用 flushSyncCallbackQueue 更新 
  7.     if (executionContext === NoContext) { 
  8.       flushSyncCallbackQueue(); 
  9.     } 
  10.   } else { 
  11.     // 異步操作 
  12.   } 

上述代碼可以簡單描述這個過程,主要是判斷了 executionContext 是否等于 NoContext 來確定當前更新流程是否在 React 事件流中。

眾所周知,React 在綁定事件時,會對事件進行合成,統一綁定到 document 上( react@17 有所改變,變成了綁定事件到 render 時指定的那個 DOM 元素),最后由 React 來派發。

所有的事件在觸發的時候,都會先調用 batchedEventUpdates$1 這個方法,在這里就會修改 executionContext 的值,React 就知道此時的 setState 在自己的掌控中。

  1. // executionContext 的默認狀態 
  2. var executionContext = NoContext; 
  3. function batchedEventUpdates$1(fn, a) { 
  4.   var prevExecutionContext = executionContext; 
  5.   executionContext |= EventContext; // 修改狀態 
  6.   try { 
  7.     return fn(a); 
  8.   } finally { 
  9.     executionContext = prevExecutionContext; 
  10.   // 調用結束后,調用 flushSyncCallbackQueue 
  11.     if (executionContext === NoContext) { 
  12.       flushSyncCallbackQueue(); 
  13.     } 
  14.   } 

所以,不管是直接調用 flushSyncCallbackQueue ,還是推遲調用,這里本質上都是同步的,只是有個先后順序的問題。

未來會有異步的 setState

如果你有認真看上面的代碼,你會發現在 scheduleUpdateOnFiber 方法內,會判斷 lane 是否為同步,那么是不是存在異步的情況?

  1. function scheduleUpdateOnFiber(fiber, lane, eventTime) { 
  2.   if (lane === SyncLane) { 
  3.     // 同步操作 
  4.     ensureRootIsScheduled(root, eventTime); 
  5.     // 判斷當前是否還在 React 事件流中 
  6.     // 如果不在,直接調用 flushSyncCallbackQueue 更新 
  7.     if (executionContext === NoContext) { 
  8.       flushSyncCallbackQueue(); 
  9.     } 
  10.   } else { 
  11.     // 異步操作 
  12.   } 

React 在兩年前,升級 fiber 架構的時候,就是為其異步化做準備的。在 React 18 將會正式發布 Concurrent 模式,關于 Concurrent 模式,官方的介紹如下。

什么是 Concurrent 模式?

Concurrent 模式是一組 React 的新功能,可幫助應用保持響應,并根據用戶的設備性能和網速進行適當的調整。在 Concurrent 模式中,渲染不是阻塞的。它是可中斷的。這改善了用戶體驗。它同時解鎖了以前不可能的新功能。

現在如果想使用 Concurrent 模式,需要使用 React 的實驗版本。

本文轉載自微信公眾號「自然醒的筆記本」,可以通過以下二維碼關注。轉載本文請聯系自然醒的筆記本公眾號。

 

責任編輯:武曉燕 來源: 自然醒的筆記本
相關推薦

2023-04-06 00:22:19

JavaScrip任務開發

2022-06-13 06:20:42

setStatereact18

2021-12-04 22:05:41

網頁任務 Performanc

2020-12-29 08:21:03

JavaScript微任務宏任務

2021-07-24 11:15:19

開發技能代碼

2022-06-13 10:24:47

宏任務微任務前端

2021-02-02 11:02:20

React任務饑餓行為優先級任務

2018-07-17 15:15:33

任務調度系統

2023-03-01 09:39:40

調度系統

2012-12-24 13:25:59

微信App

2017-04-12 11:15:52

ReactsetState策略

2021-08-23 15:14:09

Linuxat命令任務

2024-03-14 09:07:05

刷數任務維度后端

2022-09-16 08:32:17

Reduxreact

2021-02-02 14:55:48

React前端高優先

2021-06-29 09:47:34

ReactSetState機制

2025-04-07 04:00:00

教學型任務調度系統

2023-04-14 08:48:57

AutoGPT工具人工智能

2021-01-18 08:24:51

JavaScriptMicrotask微任務

2023-11-13 07:37:36

JS面試題線程
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 中文字幕一区二区三区乱码在线 | 成人免费视频 | 欧美日韩综合 | 国产成人综合在线 | 91麻豆精品国产91久久久更新资源速度超快 | 免费同性女女aaa免费网站 | 精品国产一区二区三区四区在线 | 日韩电影a | 亚洲精品视频一区二区三区 | 欧美一级黄带 | 久久亚洲一区 | 国内精品视频在线观看 | 国产精品中文字幕在线观看 | 黄网免费看 | 国产精品久久久久久久午夜片 | 久久久精品 | 请别相信他免费喜剧电影在线观看 | 久久精品视频99 | a级片网站| 国产精品久久久久久久久久免费看 | xxx视频| 亚洲精品久久久久久久久久吃药 | 欧美一级大片 | 色婷婷一区二区三区四区 | 久久久www成人免费精品 | 国产精品国产三级国产aⅴ原创 | h片在线观看网站 | 日日夜夜天天干 | 91精品国产一区二区在线观看 | 国产精品美女久久久久久免费 | 久久精品免费一区二区三 | 欧美激情在线一区二区三区 | 男女又爽又黄视频 | 亚洲国产精品久久久久婷婷老年 | 91精品国产乱码久久久久久久久 | 人人鲁人人莫人人爱精品 | 日韩毛片 | 中文字幕精 | 国产第一页在线观看 | 日本淫视频 | 欧美一级二级三级 |