Skip to content

wujie预加载原理

preload

用法

预加载指的是在应用空闲的时候requestIdleCallback将所需要的静态资源提前从网络中加载到内存中,详见preloadApp

预执行指的是在应用空闲的时候将子应用提前渲染出来,可以进一步提升子应用打开时间

只需要在preloadApp中将 exec 设置为true即可

由于子应用提前渲染可能会导致阻塞主应用的线程,所以无界提供了类似 react-fiber 方式来防止阻塞线程,详见 fiber

js
import Wujie from 'wujie-wujie-vue3'
const { preloadApp } = Wujie

preloadApp({ name: "vue3", url: "http://127.0.0.1:5174/", exec: true })
preloadApp({ name: "react", url: "http://127.0.0.1:5175/", exec: true })

preloadApp

preloadApp({ name: "vue3", url: "http://127.0.0.1:5174/", exec: true })

  1. 先合并参数,将参数合并到全局配置中
  2. 提前创建好 wujie 实例 new Wujie({ name: "vue3", url: "http://xxx", exec: true })
  3. 注册 runPreload 方法,用于执行预加载
  4. runPreload 的结果放在 sandbox 上 sandbox.preload = runPreload()

下次再加载子应用的时候,先判断 sandbox 上有没有 preload,有的话 直接取

requestIdleCallback api

requestIdleCallback是浏览器提供的一个api,用于在浏览器空闲的时候执行任务

MDNrequestIdleCallback

什么算浏览器空闲?

需要了解下 fps,

fps是每秒钟帧数,通常情况下,fps是60,也就是说每秒钟浏览器会渲染60次,所以每次渲染的时间是1000/60=16.67ms 达到60fps的时候,浏览器是最流畅的,但是如果渲染时间超过16.67ms,就会出现掉帧,也就是卡顿

浏览器一帧时间,都干了哪些事呢?

  1. 处理用户事件,就是 event 比如 click,mousemove等
  2. 执行定时器任务
  3. 执行 requestAnimationFrame
  4. 执行dom的回流与重绘
  5. 计算更新图层的绘制指令
  6. 绘制指令合并主线程 如果有空余时间会执行 requestIdleCallback

一般很难进入到第六步,因为前面五步需要执行很多任务,一般留给第六步就不多了,很难执行到。

所以一般都是第二种情况 没有任务执行时,浏览器会有50ms空闲时间,这个时间段也会执行 requestIdleCallback

将下面的脚本在浏览器控制台输出,可以看到requestIdleCallback的执行时间 永远不会超过50 因为进入的是第二种情况

js
requestIdleCallback((dedaline) => {
  console.log('requestIdleCallback', dedaline.timeRemaining()) // 49.9 永远不会超过50
})

所以,wujie 的预加载使用的就是 requestIdleCallback api 做一些预加载的工作

fiber 与 requestIdleCallback 的关系

fiber

在wujie中 fiber属性默认是 true 开启的。

fiber属性表示,js 的执行模式,由于子应用的执行会阻塞主应用的渲染线程,当设置为true时js采取类似react fiber的模式方式间断执行,每个 js 文件的执行都包裹在requestidlecallback中,每执行一个js可以返回响应外部的输入,但是这个颗粒度是js文件,如果子应用单个js文件过大,可以通过拆包的方式降低达到fiber模式效益最大化

技巧 打开主应用就需要加载的子应用可以将fiber设置为false来加快加载速度 其他场景建议采用默认值

react fiber 是 react 16 之后的一个新的调度算法,用于解决 react 之前的调度算法的问题,react 之前的调度算法是递归调用,如果组件层级很深,会导致调度时间过长,导致页面卡顿,react fiber 采用了非递归的调度算法,将递归调用改为循环调用,每次调度一小段,然后让出主线程,这样就不会阻塞主线程,提高了页面的流畅度

wujie 的 fiber 与 react fiber 有点类似,都是为了解决阻塞主线程的问题,但是 wujie 的 fiber 是为了解决子应用阻塞主应用的问题,而 react fiber 是为了解决组件层级很深导致的页面卡顿问题

react 16 并没有使用 requestIdleCallback,react相关人员调研,requestIdleCallback 有机会是20ms执行,不稳定,所以采用了 requestAnimationFrame + postMessage 的方式来实现 fiber 使用postMessage并没有使用setTimeout, 是因为setTimeout即使设置为0,其实也有个4ms的延迟,而postMessage是0ms延迟的。 到react18之后,又升级了一版,使用 MessageChannel 来实现 requestIdleCallback 的 polyfill

js
const {port1, port2} = new MessageChannel() // 只能是两个端口之间通信 port2 <-> port1
port1.onmessage = (e) => {
  console.log('MessageChannel1', e)
}
port2.onmessage = (e) => {
  console.log('MessageChannel2', e)
}
port1.postMessage('你好')
port2.postMessage('好的')