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

Error Boundaries是這么實(shí)現(xiàn)的,還挺巧妙

開發(fā) 前端
本文會(huì)講解React中Error Boundaries的完整實(shí)現(xiàn)邏輯。Error Boundaries的實(shí)現(xiàn)借助了this.setState可以傳遞callback的特性,useState暫時(shí)無(wú)法完全對(duì)標(biāo)。

[[438303]]

大家好,我卡頌。

本文會(huì)講解React中Error Boundaries的完整實(shí)現(xiàn)邏輯。

一張圖概括:

這里簡(jiǎn)單講解下React工作流程,后文有用。分為三步:

  1. 觸發(fā)更新
  2. render階段:計(jì)算更新會(huì)造成的副作用
  3. commit階段:在宿主環(huán)境執(zhí)行副作用

副作用有很多,比如:

  • 插入DOM節(jié)點(diǎn)
  • 執(zhí)行useEffect回調(diào)

好了,讓我們進(jìn)入主題。

什么是Error BoundariesReact

提供了兩個(gè)與「錯(cuò)誤處理」相關(guān)的API:

  • getDerivedStateFromError:靜態(tài)方法,當(dāng)錯(cuò)誤發(fā)生后提供一個(gè)機(jī)會(huì)渲染fallback UI
  • componentDidCatch:組件實(shí)例方法,當(dāng)錯(cuò)誤發(fā)生后提供一個(gè)機(jī)會(huì)記錄錯(cuò)誤信息

使用了這兩個(gè)API的ClassComponent通常被稱為Error Boundaries(錯(cuò)誤邊界)。

在Error Boundaries的「子孫組件」中發(fā)生的所有「React工作流程內(nèi)」的錯(cuò)誤都會(huì)被Error Boundaries捕獲。

通過(guò)開篇的介紹可以知道,「React工作流程」指:

  • render階段
  • commit階段

考慮如下代碼:

  1. class ErrorBoundary extends Component { 
  2.   componentDidCatch(e) { 
  3.     console.warn(“發(fā)生錯(cuò)誤”, e); 
  4.   } 
  5.   render() { 
  6.     return <div>{this.props.children}</div>; 
  7.   } 
  8.  
  9. const App = () => ( 
  10.  <ErrorBoundary> 
  11.     <A><B/></A> 
  12.     <C/> 
  13.  <ErrorBoundary> 

 A、B、C作為ErrorBoundary的子孫組件,當(dāng)發(fā)生「React工作流程內(nèi)」的錯(cuò)誤,都會(huì)被ErrorBoundary中的componentDidCatch方法捕獲。

步驟1:捕獲錯(cuò)誤

首先來(lái)看「工作流程中的錯(cuò)誤都是何時(shí)被捕獲的」。

render階段的核心代碼如下,發(fā)生的錯(cuò)誤會(huì)被handleError處理:

  1. do { 
  2.   try { 
  3.     // 對(duì)于并發(fā)更新則是workLoopConcurrent 
  4. workLoopSync(); 
  5.     break; 
  6.   } catch (thrownValue) { 
  7.     handleError(root, thrownValue); 
  8.   } 
  9. } while (true); 

commit階段包含很多工作,比如:

  • componentDidMount/Update執(zhí)行
  • 綁定/解綁ref
  • useEffect/useLayoutEffect callback與destroy執(zhí)行

這些工作會(huì)以如下形式執(zhí)行,發(fā)生的錯(cuò)誤被captureCommitPhaseError處理:

  1. try { 
  2. // …執(zhí)行某項(xiàng)工作  
  3. } catch (error) { 
  4.   captureCommitPhaseError(fiber, fiber.return, error); 

步驟2:構(gòu)造callback

可以發(fā)現(xiàn),即使沒(méi)有Error Boundaries,「工作流程」中的錯(cuò)誤已經(jīng)被React捕獲了。而正確的邏輯應(yīng)該是:

  • 如果存在Error Boundaries,執(zhí)行對(duì)應(yīng)API
  • 拋出React的提示信息
  • 如果不存在Error Boundaries,拋出「未捕獲的錯(cuò)誤」

所以,不管是handleError還是captureCommitPhaseError,都會(huì)從發(fā)生錯(cuò)誤的節(jié)點(diǎn)的父節(jié)點(diǎn)開始,逐層向上遍歷,尋找最近的Error Boundaries。

一旦找到,就會(huì)構(gòu)造:

  • 用于「執(zhí)行Error Boundaries API」的callback
  • 用于「拋出React提示信息」的callback

React錯(cuò)誤提示信息,包括提示語(yǔ)和錯(cuò)誤堆棧

  1.   // ...為了可讀性,邏輯有刪減 
  2. function createClassErrorUpdate() { 
  3.   if (typeof getDerivedStateFromError === 'function') { 
  4. // 用于執(zhí)行g(shù)etDerivedStateFromError的callback 
  5.     update.payload = () => { 
  6.       return getDerivedStateFromError(error); 
  7. }; 
  8. // 用于拋出React提示信息的callback 
  9.     update.callback = () => { 
  10.       logCapturedError(fiber, errorInfo); 
  11.     }; 
  12.   } 
  13.   if (inst !== null && typeof inst.componentDidCatch === 'function') { 
  14. // 用于執(zhí)行componentDidCatch的callback 
  15.     update.callback = function callback() { 
  16.       this.componentDidCatch(error); 
  17.     }; 
  18.   } 
  19.   return update

如果沒(méi)有找到Error Boundaries,繼續(xù)向上遍歷直到根節(jié)點(diǎn)。

此時(shí)會(huì)構(gòu)造:

  • 用于「拋出未捕獲錯(cuò)誤」的callback
  • 用于「拋出React提示信息」的callback
  1. // ...為了可讀性,邏輯有刪減 
  2. funffction createRootErrorUpdate() { 
  3.   // 用于拋出“未捕獲的錯(cuò)誤”及“React的提示信息”的callback 
  4.   update.callback = () => { 
  5.     onUncaughtError(error); 
  6.     logCapturedError(fiber, errorInfo); 
  7.   }; 
  8.   return update

執(zhí)行callback

構(gòu)造好的callback在什么時(shí)候執(zhí)行呢?

在React中有兩個(gè)「執(zhí)行用戶自定義callback」的API:

  • 對(duì)于ClassComponent, this.setState(newState, callback)中newState和callback參數(shù)都能傳遞Function作為callback

所以,對(duì)于Error Boundaries,相當(dāng)于主動(dòng)觸發(fā)了一次更新:

  1. this.setState(() => { 
  2.   // 用于執(zhí)行g(shù)etDerivedStateFromError的callback 
  3. }, () => { 
  4.   // 用于執(zhí)行componentDidCatch的callback 
  5.   //  以及 用于拋出React提示信息的callback 
  6. }) 
  • 對(duì)于根節(jié)點(diǎn),執(zhí)行ReactDOM.render(element, container, callback)中callback參數(shù)能傳遞Function作為callback

所以,對(duì)于「沒(méi)有Error Boundaries」的情況,相當(dāng)于主動(dòng)執(zhí)行了如下函數(shù):

  1. ReactDOM.render(element, container, () => { 
  2. // 用于拋出“未捕獲的錯(cuò)誤”及“React的提示信息”的callback 
  3. }) 

所以,Error Boundaries的實(shí)現(xiàn)可以看作是:React利用已有API實(shí)現(xiàn)的新功能。

總結(jié)

經(jīng)常有人問(wèn):為什么Hooks沒(méi)有Error Boundaries?

可以看到,Error Boundaries的實(shí)現(xiàn)借助了this.setState可以傳遞callback的特性,useState暫時(shí)無(wú)法完全對(duì)標(biāo)。

最后,給你留個(gè)作業(yè),在官方文檔[1]介紹了4種情況的錯(cuò)誤不會(huì)被Error Boundaries捕獲。

利用本文知識(shí),你能分析下他們?yōu)槭裁床粫?huì)被捕獲么?

參考資料

[1]官方文檔:

https://reactjs.org/docs/error-boundaries.html#introducing-error-boundaries

 

責(zé)任編輯:姜華 來(lái)源: 魔術(shù)師卡頌
相關(guān)推薦

2019-06-17 14:20:51

Redis數(shù)據(jù)庫(kù)Java

2019-05-27 09:14:28

2021-10-31 23:57:33

Eslint原理

2024-01-03 08:48:09

NilAway靜態(tài)分析工具

2022-09-05 08:39:55

Redis存儲(chǔ)數(shù)據(jù)

2023-03-26 00:04:14

2019-02-28 10:40:13

Windows 功能系統(tǒng)

2022-01-07 07:59:14

Go語(yǔ)言Go Error

2022-01-14 17:01:44

GoError結(jié)構(gòu)

2009-09-14 10:45:33

LINQ刪除數(shù)據(jù)

2010-01-22 16:10:12

C++ Builder

2021-12-03 06:02:19

CSS濾鏡前端

2010-08-31 13:56:38

PHP5多線程

2021-12-15 06:18:23

iOS15.2蘋果 iOS

2019-07-16 13:50:49

Windows 功能系統(tǒng)

2021-01-26 09:14:19

Linux內(nèi)核模塊

2009-11-18 15:39:43

PHP函數(shù)

2011-02-24 13:34:09

資源共享

2017-02-24 13:20:13

搜索引擎數(shù)據(jù)結(jié)構(gòu)架構(gòu)

2023-03-16 07:47:55

獨(dú)顯核顯筆記本
點(diǎn)贊
收藏

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