react原始碼解讀之ReactLazy.js

語言: CN / TW / HK

「這是我參與11月更文挑戰的第27天,活動詳情檢視:2021最後一次更文挑戰」。

Wakeable,Thenable傻傻分不清楚

```js import type {Wakeable, Thenable} from 'shared/ReactTypes'; export interface Wakeable { then(onFulfill: () => mixed, onReject: () => mixed): void | Wakeable; } export interface Thenable<+R> { then( onFulfill: (value: R) => void | Thenable | U, onReject: (error: mixed) => void | Thenable | U, ): void | Thenable; } import {REACT_LAZY_TYPE} from 'shared/ReactSymbols';

REACT_LAZY_TYPE = symbolFor('react.lazy'); `` -Wakeable,可喚醒的。這樣一個介面規定實現它的類,必須實現一個then方法,這個then方法的返回值型別為void(空)或者Wakeable。它接收兩個函式引數,成功時的回撥和失敗時的回撥。 -Thenable介面的定義與Wakeable的定義類似,只是函式引數的入參不一樣,ThenableonFulfill方法的返回值可以為Thenable,也就是說可以無限地往下then下去。 -REACT_LAZY_TYPE識別符號標識了react的懶載入型別,讀完原始碼你會知道react`懶載入型別有何作用。 如果這裡不太明白,建議繼續往下看,山窮水復疑無路,柳暗花明又一村,不要在這顆樹上吊死了。

問題Wakeable與Thenable有何不一樣?

Thenable的狀態值

js const Uninitialized = -1; const Pending = 0; const Resolved = 1; const Rejected = 2; - Uninitialized,表示未初始化,值為-1。 - Pending,表示正在載入中,值為0。 - Resolved,表示已經載入完成並且載入成功,值為1。 - Rejected,表示已經載入完成但是載入失敗,值為2。

真的值得嗎?

payload表示有效載荷,關鍵資訊 假設Thenable方法會返回一個未知量,那麼這個未知量代表什麼呢? 請閱讀下面的程式碼:

```js type UninitializedPayload = { _status: -1, _result: () => Thenable<{default: T, ...}>, };

type PendingPayload = { _status: 0, _result: Wakeable, };

type ResolvedPayload = { _status: 1, _result: {default: T}, };

type RejectedPayload = { _status: 2, _result: mixed, }; `` 根據狀態值,將有效載荷分為4種類型。 -UninitializedPayload`,未初始化的有效載荷,_result屬性為一個函式返回一個Thenable。 - PendingPayload,載入中的有效載荷,_result屬性為一個Wakeable. - ResolvedPayload,已完成的有效載荷,_result屬性為一個物件,預設值為泛型T對應的資料型別。 - RejectedPayload,已失敗的有效載荷,—result屬性為mixed,表示任意型別。 可以看到,在Resolved階段,返回的是任意資料型別(mixed),這個mixed又由Wakeable返回,也就是載入中有效載荷的_result屬性執行後返回。未初始化的有效載荷的_result屬性呼叫後,返回一個Thenable,這個Thenable會返回一個Wakeable,也就是將會返回實際資料的一個函式。ResolvedPayload就是我們實際所需要的資料。

爆炸,就簡簡單單的一個非同步呼叫返回資料的功能,被設計成了四層。這真的值得嗎?

ctor是個什麼der

```js

export function lazy(ctor) { const payload = { _status: Uninitialized, _result: ctor, };

const lazyType = { $$typeof: REACT_LAZY_TYPE, _payload: payload, _init: lazyInitializer, }; return lazyType; } ``` 最後,react匯出了一個lazy函式,萬事大吉。

ctor是個什麼der?

首先,我們看看React.lazy這個api的使用。

js const LazyComponent = React.lazy(() => import('../componets/LazyComponent)); 可以看到,ctor是一個函式,這個函式返回一個Thenable的非同步呼叫。

js function resolveLazy(lazyType) { const payload = lazyType._payload; const init = lazyType._init; return init(payload); } function lazyInitializer(payload) { if (payload._status === Uninitialized) { const ctor = payload._result; const thenable = ctor(); thenable.then() ... } resolveLazy方法會呼叫lazyInitializer的_init方法,最開始,會進入未初始化的狀態判斷。 呼叫ctor得到一個thenable的物件。在非同步呼叫過程中,payload的狀態將是Pending。 呼叫結束之後會返回moduleObject.default,返回這個元件渲染所必須的payload。

非同步路由不夠,第三方包也要非同步。

在一個專案的迭代過程中,隨著模組的越來越多,webpack打包的第三方包將會越來越多,這樣導致系統首次載入將會越來越慢。雖然有了非同步路由的加持,但是在main.js檔案里加入過多的檔案,專案大到一定程度,仍將導致主入口檔案的體積過大。React的lazy方法值得我們學習,去處理專案第三方包過多的問題。

感謝閱讀,歡迎動動你的小手,給個贊吧。