Skip to content

预加载子应用

空闲时加载

主要原理是利用 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);
  })
}