react原始碼解讀之ReactLazy.js
「這是我參與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的定義類似,只是函式引數的入參不一樣,
Thenable的
onFulfill方法的返回值可以為
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
type PendingPayload = { _status: 0, _result: Wakeable, };
type ResolvedPayload
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方法值得我們學習,去處理專案第三方包過多的問題。
感謝閱讀,歡迎動動你的小手,給個贊吧。