qiankun 是如何实现 JS 隔离的?
参考答案:
qiankun 是基于 single-spa 实现的微前端框架,它通过沙箱机制实现了 JavaScript 的隔离,主要依赖 快照沙箱 和 Proxy 沙箱 来管理子应用的 JavaScript 环境。
以下是 qiankun 实现 JS 隔离的具体原理:
1. 沙箱机制
qiankun 使用沙箱技术隔离子应用的 JavaScript 执行环境,避免子应用之间以及子应用和主应用之间的全局变量污染。具体实现方式分为两种:
(1)快照沙箱
原理:
- 在加载子应用之前,保存
window和document上的所有全局变量的快照(初始状态)。 - 当子应用运行时,记录子应用对全局变量的修改。
- 当子应用被卸载时,恢复全局变量为快照保存的状态。
- 在加载子应用之前,保存
实现代码:
javascriptclass SnapshotSandbox { constructor() { this.active = false; this.windowSnapshot = {}; } // 激活沙箱 activate() { if (!this.active) { this.windowSnapshot = { ...window }; // 保存快照 this.active = true; } } // 恢复沙箱 deactivate() { if (this.active) { Object.keys(window).forEach((key) => { if (!(key in this.windowSnapshot)) { delete window[key]; // 删除新增的全局变量 } else { window[key] = this.windowSnapshot[key]; // 恢复修改的全局变量 } }); this.active = false; } } }优点:
- 实现简单,兼容性好。
- 适用于子应用之间没有并行运行的场景。
缺点:
- 无法支持多实例并行运行。
- 恢复状态时性能可能较差。
(2)Proxy 沙箱
原理: 通过 ES6 的
Proxy拦截对子应用全局对象(window)的访问,创建一个伪造的全局对象供子应用使用。子应用操作的实际上是Proxy对象,而不是原生window。实现代码:
javascriptclass ProxySandbox { constructor() { this.proxy = new Proxy(window, { get(target, key) { return key in this.fakeWindow ? this.fakeWindow[key] : target[key]; }, set(target, key, value) { this.fakeWindow[key] = value; return true; }, }); this.fakeWindow = {}; // 伪造的全局对象 this.active = false; } activate() { this.active = true; } deactivate() { this.active = false; this.fakeWindow = {}; } }优点:
- 支持多实例隔离(不同子应用实例可以运行在不同的
Proxy上)。 - 性能较好,且子应用与全局对象完全隔离。
- 支持多实例隔离(不同子应用实例可以运行在不同的
缺点:
- 需要现代浏览器支持
Proxy。
- 需要现代浏览器支持
2. 沙箱的动态绑定
在 qiankun 中,沙箱会根据子应用的生命周期进行动态切换:
- 加载子应用时:启用沙箱,挂载子应用代码,修改的全局变量会保留在沙箱中。
- 卸载子应用时:停用沙箱,恢复主应用的全局环境。
- 并行运行多个子应用时:通过独立的
Proxy实例实现每个子应用的环境隔离。
3. 微前端框架的挂载和卸载流程
结合沙箱,qiankun 的子应用加载流程如下:
加载子应用资源:
- 通过
fetch加载子应用的 HTML、CSS 和 JavaScript。 - 动态插入
script标签以运行子应用代码。
- 通过
运行子应用代码:
- 使用沙箱(
Proxy或快照)控制代码的执行环境。 - 子应用的全局变量、事件监听等都仅限于其沙箱范围内。
- 使用沙箱(
卸载子应用:
- 停用沙箱,清理子应用的副作用(如事件监听、全局变量)。
4. 样式隔离
除了 JS 隔离,qiankun 还会对样式进行隔离,防止子应用的样式污染全局:
- CSS 前缀隔离: 为子应用的样式规则添加特定的前缀(如
data-app="app1"),使其作用范围限制在子应用内。 - Shadow DOM: 使用
Shadow DOM为子应用创建独立的样式作用域。
题目要点:
qiankun 的 JS 隔离主要依赖于以下技术:
- 快照沙箱:适合简单场景,兼容性好,但不支持多实例。
- Proxy 沙箱:适合复杂场景,支持多实例并行运行,性能更好。
- 结合子应用生命周期,动态启用和停用沙箱。
- 配合 CSS 隔离 和其他隔离手段,全面防止子应用对全局的干扰。