Fancy Front End Fancy Front End
  • 开始上手
  • 基础
  • 调度器(Scheduler)
  • 更新器(Updater)
  • 渲染器(Render)
  • 更新周期
  • hooks 原理
  • 总结
  • 📙 React源码漂流记
  • 开始上手
  • 基础
  • reactivity
  • runtime-core
  • runtime-dom
  • Awesome Web
  • Awesome NodeJS
话题
  • 导航
  • Q&A
  • 幻灯片
  • 关于
  • 分类
  • 标签
  • 归档
博客 (opens new window)
GitHub (opens new window)

Jonsam NG

让有意义的事变得有意思,让有意思的事变得有意义
  • 开始上手
  • 基础
  • 调度器(Scheduler)
  • 更新器(Updater)
  • 渲染器(Render)
  • 更新周期
  • hooks 原理
  • 总结
  • 📙 React源码漂流记
  • 开始上手
  • 基础
  • reactivity
  • runtime-core
  • runtime-dom
  • Awesome Web
  • Awesome NodeJS
话题
  • 导航
  • Q&A
  • 幻灯片
  • 关于
  • 分类
  • 标签
  • 归档
博客 (opens new window)
GitHub (opens new window)
  • 开始上手
  • Plan 计划
  • typescript-utility

  • single-spa源码

    • 开始阅读
    • app与应用管理

    • lifecycles与生命周期管理

      • 本章概要
      • 生命周期:load 和 unload
      • 生命周期:bootstrap
        • 目录
        • toBootstrapPromise
        • reasonableTime
      • 生命周期:mount 和 unmount
      • 生命周期:update
    • navigation与路由管理

    • parcel组件

    • 其他

    • single-spa-react

  • qiankun源码

  • webpack

  • axios

  • solid

  • vite源码

  • jquery源码

  • snabbdom

  • am-editor

  • html2canvas

  • express

  • acorn源码

  • immutable.js源码

  • web
  • single-spa源码
  • lifecycles与生命周期管理
jonsam
2022-04-18
目录

生命周期:bootstrap

本节讲解 single-spa 中生命周期 bootstrap 函数的原理。在 single-spa 中 bootstrap 是在 load 阶段之后、mount 阶段之前的阶段。bootstrap 阶段的主要任务就是执行 bootstrap 生命周期钩子,bootstrap 钩子可以理解为 beforeMount 钩子。

# 目录

  • 目录
  • toBootstrapPromise
  • reasonableTime

# toBootstrapPromise

代码如下。

export function toBootstrapPromise(appOrParcel, hardFail) {
  return Promise.resolve().then(() => {
    if (appOrParcel.status !== NOT_BOOTSTRAPPED) {
      return appOrParcel;
    }
    // 将状态修改为 BOOTSTRAPPING
    appOrParcel.status = BOOTSTRAPPING;
    // 如果没有 bootstrap 钩子,则使用默认的钩子
    if (!appOrParcel.bootstrap) {
      // Default implementation of bootstrap
      return Promise.resolve().then(successfulBootstrap);
    }
    // 调用声明周期函数并且应用 timeout 超时时间配置
    return reasonableTime(appOrParcel, "bootstrap")
      .then(successfulBootstrap)
      .catch((err) => {
        if (hardFail) {
          throw transformErr(err, appOrParcel, SKIP_BECAUSE_BROKEN);
        } else {
          handleAppError(err, appOrParcel, SKIP_BECAUSE_BROKEN);
          return appOrParcel;
        }
      });
  });

  function successfulBootstrap() {
    appOrParcel.status = NOT_MOUNTED;
    return appOrParcel;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

toBootstrapPromise 的主要工作总结如下:

  • 执行 bootstrap 生命周期钩子。
  • 初始化时将 app.status 更新为 BOOTSTRAPPING,执行钩子任务出现错误时将状态更新为 SKIP_BECAUSE_BROKEN,钩子任务执行成功后将转台更新为 NOT_MOUNTED。

# reasonableTime

按照 timeout 超时时间的配置执行生命周期钩子,并且返回执行结果 promise。

app.timeouts 是在 load 阶段初始化的。

export function reasonableTime(appOrParcel, lifecycle) {
  // 获取 timeouts 配置
  const timeoutConfig = appOrParcel.timeouts[lifecycle];
  const warningPeriod = timeoutConfig.warningMillis;
  // 应用的类型
  const type = objectType(appOrParcel);

  return new Promise((resolve, reject) => {
    let finished = false;
    let errored = false;
    // 调用钩子函数(在 load 阶段已经转换为 reduce pipeline)
    // 传入相关属性,因为这里是异步的不影响后面在 setTimeout 中
    // 使用 warningPeriod 和 timeoutConfig.millis
    appOrParcel[lifecycle](getProps(appOrParcel))
      .then((val) => {
        // 将管道执行的结果 resolve
        finished = true;
        resolve(val);
      })
      .catch((val) => {
        finished = true;
        reject(val);
      });
    // 在 warningPeriod 之后判断是否需要 warning
    setTimeout(() => maybeTimingOut(1), warningPeriod);
    // 在 timeoutConfig.millis 之后绝对是否需要终止
    setTimeout(() => maybeTimingOut(true), timeoutConfig.millis);

    const errMsg = formatErrorMessage(
      // ......
    );

    function maybeTimingOut(shouldError) {
      // 没有 finished 才需要 warning 和 stop
      if (!finished) {
        if (shouldError === true) {
          errored = true;
          // 如果配置 dieOnTimeout,则超时 reject 即可
          if (timeoutConfig.dieOnTimeout) {
            reject(Error(errMsg));
          } else {
            // 即时超时也要等待应用生命周期执行完毕
            console.error(errMsg);
            //don't resolve or reject, we're waiting this one out
          }
        } else if (!errored) {
          // shouldError 是数字表示 waning 重试次数
          const numWarnings = shouldError;
          // 重试时间
          const numMillis = numWarnings * warningPeriod;
          console.warn(errMsg);
          // 重试 waning,直到 finished
          if (numMillis + warningPeriod < timeoutConfig.millis) {
            setTimeout(() => maybeTimingOut(numWarnings + 1), warningPeriod);
          }
        }
      }
    }
  });
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

这里比较巧妙的是报错和报警的处理和任务队列的处理。

生命周期的钩子数组处理为任务数组(回调数组),以 promise 的方式在微任务中逐个执行,执行所有的任务都完成。这对于简单的任务队列是可以参考的,而反观 React 中调度器中的任务队列,实际上是实现了更为复杂的功能包括基于优先级的回调、任务的中断与恢复、任务的时间切片等。

这样的简单任务队列在 promise 的支持下也实现了任务的切片执行,这使得计算量较大的任务可以单独在一个微任务中执行,这提高了任务执行的效率,同时整个任务的执行过程也变得异步。

maybeTimingOut 可以对任务队列的超时状况进行报警,方便开发者进行性能调优和错误监控。

编辑 (opens new window)
上次更新: 2022/09/06, 14:25:16
生命周期:load 和 unload
生命周期:mount 和 unmount

← 生命周期:load 和 unload 生命周期:mount 和 unmount→

最近更新
01
渲染原理之组件结构与 JSX 编译
09-07
02
计划跟踪
09-06
03
开始上手
09-06
更多文章>
Theme by Vdoing | Copyright © 2022-2022 Fancy Front End | Made by Jonsam by ❤
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式