生命周期:bootstrap
本节讲解 single-spa 中生命周期 bootstrap 函数的原理。在 single-spa 中 bootstrap 是在 load 阶段之后、mount 阶段之前的阶段。bootstrap 阶段的主要任务就是执行 bootstrap 生命周期钩子,bootstrap 钩子可以理解为 beforeMount
钩子。
# 目录
# 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
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
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