# ReactLazy

文件地址:react/src/ReactLazy.js

处理异步React组件。

# lazy

function lazy(ctor) {
  const payload = {
    _status: -1, // 当前状态
    _result: ctor, // 
  };
  
  // 返回了一个lazyComponent Element
  const lazyType = {
    $$typeof: REACT_LAZY_TYPE,
    _payload: payload,
    _init: lazyInitializer,
  };
  
  return lazyType;
}

# lazyInitializer

const Uninitialized = -1;
const Pending = 0;
const Resolved = 1;
const Rejected = 2;

function lazyInitializer(payload) {
  // 如果调度器处理当前 LazyComponent 未初始化,执行loader并记录对应状态
  if (payload._status === Uninitialized) {
    const ctor = payload._result;
    const thenable = ctor(); // 这里是import()返回的promise对象
    const pending = payload;
    pending._status = Pending;
    pending._result = thenable;
    thenable.then( // 请求成功了
      moduleObject => {
        if (payload._status === Pending) { // 当前仍处于请求状态时
          const defaultExport = moduleObject.default;
          const resolved = payload;
         	resolved._status = Resolved; // 状态修改
          resolved._result = defaultExport; // 导出异步文件内容
        }
      },
      error => {
        if (payload._status === Pending) {
          const rejected = payload;
          rejected._status = Rejected; // 状态修改
          rejected._result = error;
        }
      }
    );
  }

  // 如果调度器处理当前 LazyComponent 时已经初始化成功,直接将 promise.resolve 结果返回
  // 这里可以避免重复import情况
  if (payload._status === Resolved) {
    return payload._result;
  } else {
    // 失败 或 promise 仍未执行完,将 error 或者 promise 抛出
    throw payload._result;
  }
}

LazyComponent的加载逻辑中,核心原则是:

  • 加载完成后直接返回组件模块本身
  • 加载失败抛出错误
  • 首次加载或加载中的组件将promise对象以throw Error的方式抛出

# 整体流程

# Lazy Element生成

Lazy函数返回了一个Lazy Element。

function lazy(ctor) {
  // 返回了一个lazyComponent Element
  const lazyType = {
    $$typeof: REACT_LAZY_TYPE,
    _payload: payload,
    _init: lazyInitializer,
  };
  
  return lazyType;
}

# Lazy Element解析

React针对Lazy Element有特殊的解析方式

case LazyComponent: {
  const elementType = workInProgress.elementType;
  return mountLazyComponent(
    current,
    workInProgress,
    elementType,
    updateLanes,
    renderLanes,
  );
}
function mountLazyComponent(
	_current,
	workInProgress,
  elementType,
   updateLanes,
   renderLanes,
) {
    // ...
    const init = lazyComponent._init; // lazyInitializer
  	let Component = init(payload);
    // ...
}

# 使用方式

import()函数是TS39提出的动态加载模块的规范实现,其返回一个Promise

import React, { lazy, Suspense } from 'react';

const OtherComponent = lazy(() => import('./OtherComponent')); // 这里返回了一个lazy对象,每次重render不会生成新的对象

function MyComponent() {
  return (
  	<div>
    	<Suspense fallback={<div>Loading...</div>}>
      	<OtherComponent />
      </Suspense>
    </div>
  );
}
最近更新时间: 2023/8/22 17:55:30