feng xiaohan

Wujie 简介

由腾讯开发的微前端框架,帮助开发者将复杂的前端项目拆分为多个微前端应用,实现分治开发、独立部署、统一集成的目标。

拥有以下几个特点(官网):

极速

页面切换时速度快,无白屏。(主要是通过开启预加载实现)

预加载

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

主流的 PC 屏幕刷新率(FPS)大多在 60Hz,即 1 秒钟对屏幕进行 60 次刷新,平均每次刷新耗时大概是 16.6ms。

requestidlecallback触发的时机有两种:

  • 在一帧的输入渲染合成完成后才会有空闲时间触发requestidlecallback;

    一帧内所做的事情如下:

    • 输入事件处理:浏览器会处理用户的输入事件,如鼠标点击、键盘输入等,并将这些事件放入事件队列中;
    • JavaScript 执行:浏览器会从事件队列中取出事件并执行对应的 JavaScript 代码,如事件处理函数、定时器等;
    • 执行 requestAnimationFrame;
    • 执行 dom 的回流与重绘;
    • 计算更新图层的绘制指令(浏览器会将布局信息转换成绘制指令,并使用 GPU 进行绘制渲染,生成对应的位图);
    • 绘制指令合并主线程(浏览器会将多个位图进行合成,生成最终的页面图像),如果有空余时间会执行 requestidlecallback

    在这个过程中,浏览器会尽可能地优化渲染流程,以提高页面的渲染性能和用户体验。实际上就是在 16.6ms 之内完成输入渲染合成,空闲的时间才会留给 requestidlecallback

  • 没有任务执行浏览器会有 50ms 空闲时间,这个时间段也会执行 requestidlecallback

    例如直接在控制台输出。

requestidlecallback(function (deadline) {
  console.log(deadline.timeRemaining());
});

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

react16: postMessage + requestAnimationFrame来实现类似requestidlecallback()的功能;

  • 使用postMessage + requestAnimationFrame是因为 react 开发人员经过测试发现requestidlecallback()可能会超过 16ms,超过 16ms 绘制就会看起来很卡,所以 react16 是用postMessage + requestAnimationFrame实现的。
  • 使用postMessage 来代替setTimeOut()是因为后者即使为 0

react18 :使用MessageChannel实现requestidlecallback()

强大

支持子应用保活、内嵌、去中心化通信、多应用激活。

子应用保活

简单

框架封装,保持普通组件使用体验一致。

原生隔离

基于 WebComponent 和 iframe,原生物理隔离。

WebComponent

window.onload = () => {
  class Wujie extends HTMLElement {
    constructor() {
      super();
      // shadowdom 样式隔离
      let dom = this.attachShadow({ mode: "open" });
      let template = document.querySelector("#wujie") as HTMLTemplateElement;

      dom.appendChild(template.content.cloneNode(true));

      console.log(this.getAttr("name"), this.getAttr("url"));
    }
    private getAttr(attr: string) {
      return this.getAttribute(attr);
    }

    // webComponents的生命周期
    connectedCallback() {
      console.log("类似于vue的mounted");
    }
    disconnectedCallback() {
      console.log("类似于vue的destory");
    }
    attributeChangedCallback(name: any, oldVal: any, newVal: any) {
      console.log("类似于vue的watch");
    }
  }
  // 使用原生js挂载一个组件
  window.customElements.define("wu-jie", Wujie);
};
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="./index.js"></script>
  </head>
  <body>
    <wu-jie name="fdsf" url="dsafas"></wu-jie>
    <div>我是外层的div</div>

    <template id="wujie">
      <style>
        div {
          background: red;
        }
      </style>
      <div>我是template里面的div</div>
    </template>
  </body>
</html>

iframe

将 js 单独存放在 iframe 中。

原生性能

避免 with 语句运行代码,整体的运行性能接近原生。

开箱即用

主、子应用无需做任何适配,开箱即用。

小结

缺陷

  • 隔离 js 使用一个空的 iframe 进行隔离。
  • 子应用 axios 需要自行适配。
  • iframe 沙箱的 src 设置了主应用的 host,初始化 iframe 的时候需要等待 iframe 的 location.orign 从’about:blank’初始化为主应用的 host,这个采用的计时器去等待的不是很优雅。

底层原理:使用 shadowDom 隔离 css,js 使用空的 iframe 隔离,通讯使用的是 proxy。