预加载子应用
空闲时加载
主要原理是利用
window.requestIdleCallback
API,详细介绍 requestAnimationFrame&requestIdleCallback
qiankun预加载子应用分为
prefetchImmediately
首次全部加载和prefetchAfterFirstMounted
第一个子应用挂载后开始预加载
prefetchImmediately
调用start后,开始预加载所有子应用. 只加载子应用资源(缓存起来),不执行;
主子应用处于同一个域而且是http1/1的话请求并发由于受到限制,可能导致首屏渲染变慢.
适用场景: 如果是展示各类子应用的home页面,点击不同链接跳转子应用,可配置成all,当使用$router.push跳转时生效。使用window.open或location.href跳转的方式则无效, 因为qiankun对已缓存的资源储存在内存中,新开的页面需要则重新使用fetch请求
js
// 初始化时加载所有应用资源
export function prefetchImmediately(apps) {
apps.forEach(({ entry }) => prefetch(entry))
}
// prefetch
function prefetch(entry) {
// 空闲时间加载 子应用&子应用资源(script/sytle)
requestIdleCallback(async () => {
// importEntry加载子应用入口文件,并返回getExternalScripts, getExternalStyleSheets方法
// 调用这俩方法会加载对应子应用入口文件中的script、style的资源文件,最终返回promise
// 【对于请求过的资源url,importEntry会添加缓存,下次直接返回结果 也就是不用再次请求资源了】
const { getExternalScripts, getExternalStyleSheets } = await importEntry(entry, opts)
requestIdleCallback(getExternalStyleSheets)
requestIdleCallback(getExternalScripts)
})
}
// requestidlecallback
const requestIdleCallback =
window.requestIdleCallback ||
function requestIdleCallback(cb) {
const start = Date.now()
return setTimeout(() => {
cb({
didTimeout: false,
timeRemaining() {
return Math.max(0, 50 - (Date.now() - start))
}
})
}, 1)
}
prefetchAfterFirstMounted
通过监听
single-spa:first-mount
事件等待第一个子应用挂载mount完成后开始预加载其他子应用
适用场景: 首屏挂载子应用,等待挂载完成后预加载其他子应用
js
function prefetchAfterFirstMounted(apps: AppMetadata[], opts?: ImportEntryOpts): void {
// 监听single-spa发布的first-mout钩子,第一个子应用加载完成后开始加载其他子应用
window.addEventListener('single-spa:first-mount', function listener() {
// 判断是否加载过
const notLoadedApps = apps.filter((app) => getAppStatus(app.name) === NOT_LOADED);
// 开始预载
notLoadedApps.forEach(({ entry }) => prefetch(entry, opts));
// 加载启动,移除监听
window.removeEventListener('single-spa:first-mount', listener);
})
}