第五章:高级特性与优化 🚀
5.1 沙箱机制深度解析
5.1.1 沙箱机制概述
沙箱机制是微前端架构中的核心技术,它确保不同子应用之间的 JavaScript 执行环境相互隔离,防止全局变量污染和冲突。
沙箱机制的核心目标:
- 隔离性:不同子应用的 JavaScript 执行环境完全隔离
- 安全性:防止恶意代码影响其他应用
- 性能:最小化沙箱带来的性能开销
- 兼容性:支持各种 JavaScript 特性和 API
5.1.2 快照沙箱(SnapshotSandbox)
快照沙箱是 qiankun 中最基础的沙箱实现,通过记录和恢复 window 对象的状态来实现隔离。
快照沙箱实现:
//
export class SnapshotSandbox {
private windowSnapshot: Record<string, any> = {};
private modifyPropsMap: Record<string, any> = {};
private running = false;
constructor() {
this.init();
}
private init() {
// 初始化时记录 window 的初始状态
this.windowSnapshot = {};
for (const prop in window) {
this.windowSnapshot[prop] = window[prop];
}
}
// 激活沙箱
active() {
if (this.running) {
return;
}
this.running = true;
// 恢复之前修改的属性
for (const prop in this.modifyPropsMap) {
window[prop] = this.modifyPropsMap[prop];
}
}
// 失活沙箱
inactive() {
if (!this.running) {
return;
}
this.running = false;
// 记录当前修改的属性
for (const prop in window) {
if (window[prop] !== this.windowSnapshot[prop]) {
this.modifyPropsMap[prop] = window[prop];
// 恢复原始状态
window[prop] = this.windowSnapshot[prop];
}
}
}
// 销毁沙箱
destroy() {
this.inactive();
this.windowSnapshot = {};
this.modifyPropsMap = {};
}
}
快照沙箱的优缺点:
优点:
- 实现简单,兼容性好
- 对现有代码影响小
- 支持所有 JavaScript 特性
缺点:
- 只能同时运行一个子应用
- 性能开销较大
- 无法完全隔离全局变量
使用示例:
// 1. 创建沙箱实例
const sandbox = new SnapshotSandbox();
// 2. 激活沙箱(子应用启动时)
sandbox.active();
// 此时子应用可以正常使用 window 对象
// 例如:子应用代码中
window.myAppName = "sub-app-1";
window.myAppConfig = { version: "1.0.0" };
// 3. 失活沙箱(子应用卸载时)
sandbox.inactive();
// 此时 window 对象会恢复到沙箱激活前的状态
// window.myAppName 和 window.myAppConfig 会被清除
// 4. 再次激活沙箱(子应用重新启动时)
sandbox.active();
// 此时会恢复之前修改的属性
// window.myAppName 和 window.myAppConfig 会恢复为 'sub-app-1' 和 { version: '1.0.0' }
// 5. 销毁沙箱(不再需要时)
sandbox.destroy();
完整使用场景示例:
// 微前端框架中的使用
class MicroApp {
private sandbox: SnapshotSandbox;
private appName: string;
constructor(appName: string) {
this.appName = appName;
// 为每个子应用创建独立的沙箱实例
this.sandbox = new SnapshotSandbox();
}
// 启动子应用
async mount() {
// 激活沙箱
this.sandbox.active();
// 加载并执行子应用代码
const appCode = await this.loadAppCode();
eval(appCode); // 在实际场景中,应该使用更安全的方式执行代码
console.log(`子应用 ${this.appName} 已启动`);
}
// 卸载子应用
async unmount() {
// 失活沙箱,恢复 window 对象
this.sandbox.inactive();
console.log(`子应用 ${this.appName} 已卸载`);
}
// 销毁子应用
destroy() {
// 销毁沙箱
this.sandbox.destroy();
console.log(`子应用 ${this.appName} 已销毁`);
}
private async loadAppCode(): Promise<string> {
// 加载子应用代码的逻辑
return "";
}
}
// 使用示例
const app1 = new MicroApp("app1");
const app2 = new MicroApp("app2");
// 启动第一个应用
await app1.mount();
// 此时 window 对象被 app1 修改
// 卸载第一个应用
await app1.unmount();
// 此时 window 对象恢复到初始状态
// 启动第二个应用
await app2.mount();
// 此时 window 对象被 app2 修改,但不会受到 app1 的影响
// 卸载第二个应用
await app2.unmount();
// 此时 window 对象恢复到初始状态
注意事项:
- 单实例限制:快照沙箱只能同时运行一个子应用,如果需要同时运行多个应用,应该使用
ProxySandbox - 生命周期管理:确保在子应用卸载时调用
inactive(),避免全局变量污染 - 性能考虑:快照沙箱需要遍历整个 window 对象,性能开销较大,适合单应用场景
- 兼容性:快照沙箱兼容所有浏览器,包括不支持 Proxy 的旧浏览器
5.1.3 代理沙箱(ProxySandbox)
代理沙箱使用 ES6 的 Proxy 特性,通过代理 window 对象来实现更精细的隔离控制。
代理沙箱实现:
// src/sandbox/ProxySandbox.ts
export class ProxySandbox {
private proxy: Window;
private running = false;
private sandboxRunning = false;
constructor() {
this.proxy = this.createProxy();
}
private createProxy(): Window {
const rawWindow = window;
const fakeWindow = {} as Window;
/**
* 问题 1:Proxy 的第一个参数应该是 fakeWindow 还是 rawWindow?
*
* 答案:应该是 fakeWindow
*
* 原因:
* 1. 所有子应用的修改都应该记录到 fakeWindow 中,实现隔离
* 2. 当访问属性时,优先从 fakeWindow 获取(子应用自己的属性)
* 3. 如果 fakeWindow 中没有,才从 rawWindow 获取(全局共享的属性)
*
* 注意:也有实现使用 new Proxy(window, ...),但那样需要更复杂的拦截逻辑
*/
return new Proxy(fakeWindow, {
get(target, key) {
// target 指向 fakeWindow
// 优先从代理对象(fakeWindow)获取
if (key in target) {
const value = target[key];
/**
* 问题 2:如果 value 是 function,应该 bind 到 fakeWindow 还是 rawWindow?
*
* 答案:应该 bind 到 fakeWindow
*
* 原因:
* 1. 如果函数是子应用自己定义的(存储在 fakeWindow 中),
* 应该 bind 到 fakeWindow,这样函数内部的 this 指向 fakeWindow
* 2. 例如:window.myFunc = function() { return this.myVar; }
* 调用时,this 应该是 fakeWindow,而不是 rawWindow
*/
if (typeof value === "function") {
return value.bind(fakeWindow);
}
return value;
}
// 从原始 window 获取
const value = rawWindow[key];
/**
* 对于从 rawWindow 获取的函数,应该 bind 到 rawWindow
*
* 原因:
* 1. 这些是浏览器原生的 API(如 addEventListener、setTimeout 等)
* 2. 它们需要在真实的 window 上下文中执行
* 3. 例如:window.addEventListener 需要在真实的 window 上添加事件监听器
*/
if (typeof value === "function") {
return value.bind(rawWindow);
}
return value;
},
set(target, key, value) {
if (this.sandboxRunning) {
target[key] = value;
}
return true;
},
has(target, key) {
return key in target || key in rawWindow;
},
deleteProperty(target, key) {
if (this.sandboxRunning) {
delete target[key];
}
return true;
},
ownKeys(target) {
return Reflect.ownKeys(rawWindow);
},
getOwnPropertyDescriptor(target, key) {
return Reflect.getOwnPropertyDescriptor(rawWindow, key);
},
defineProperty(target, key, descriptor) {
if (this.sandboxRunning) {
return Reflect.defineProperty(target, key, descriptor);
}
return true;
},
});
}
// 激活沙箱
active() {
if (this.running) {
return;
}
this.running = true;
this.sandboxRunning = true;
}
// 失活沙箱
inactive() {
if (!this.running) {
return;
}
this.running = false;
this.sandboxRunning = false;
}
// 获取代理对象
getProxy() {
return this.proxy;
}
}
关键问题详解:
-
为什么 Proxy 的第一个参数是 fakeWindow?
new Proxy(fakeWindow, ...)表示代理的是fakeWindow对象- 所有对代理对象的操作(get/set)都会作用在
fakeWindow上 - 这样确保了子应用的修改都记录在
fakeWindow中,不会污染rawWindow - 当访问属性时,优先从
fakeWindow获取,实现了隔离
-
函数绑定的两种场景:
场景 A:从 fakeWindow 获取的函数(子应用定义的)
// 子应用代码:window.myFunc = function() { return this.myVar; } // 这个函数存储在 fakeWindow 中 // 应该 bind 到 fakeWindow,这样 this.myVar 访问的是 fakeWindow.myVar if (key in target) { // target 是 fakeWindow const value = target[key]; if (typeof value === "function") { return value.bind(fakeWindow); // ✅ 正确 } }场景 B:从 rawWindow 获取的函数(浏览器原生 API)
// 浏览器原生 API:window.addEventListener、window.setTimeout 等 // 这些函数需要在真实的 window 上下文中执行 const value = rawWindow[key]; if (typeof value === "function") { return value.bind(rawWindow); // ✅ 正确 } -
两种实现方式对比:
方式一:
new Proxy(fakeWindow, ...)(当前实现)- ✅ 优点:逻辑清晰,所有修改都在 fakeWindow 中
- ✅ 优点:隔离性更好
- ⚠️ 注意:需要区分函数来源,分别绑定
方式二:
new Proxy(window, ...)(另一种实现)- ✅ 优点:可以直接访问 window 的所有属性
- ⚠️ 缺点:需要更复杂的拦截逻辑,将修改重定向到 fakeWindow
- ⚠️ 缺点:需要维护 updatedValueSet 来跟踪哪些属性被修改过
代理沙箱的优缺点:
优点:
- 可以同时运行多个子应用
- 性能更好
- 隔离性更强
缺点:
- 需要 ES6 Proxy 支持
- 实现复杂
- 某些特殊场景可能有兼容性问题
5.1.4 沙箱选择策略
沙箱选择决策树:
// src/sandbox/SandboxSelector.ts
export class SandboxSelector {
static selectSandbox(options: {
strictStyleIsolation?: boolean;
experimentalStyleIsolation?: boolean;
singular?: boolean;
}) {
const { strictStyleIsolation, experimentalStyleIsolation, singular } =
options;
// 如果启用了严格样式隔离,使用代理沙箱
if (strictStyleIsolation || experimentalStyleIsolation) {
return new ProxySandbox();
}
// 如果只能运行一个应用,使用快照沙箱
if (singular) {
return new SnapshotSandbox();
}
// 默认使用代理沙箱
return new ProxySandbox();
}
}
5.2 性能优化策略
5.2.1 预加载机制
预加载机制可以在空闲时间预先加载子应用资源,提升用户体验。
预加载实现:
// src/performance/Preloader.ts
export class Preloader {
private loadedApps = new Set<string>();
private loadingApps = new Set<string>();
private preloadQueue: string[] = [];
constructor(private appConfigs: any[]) {
this.setupIdleCallback();
}
private setupIdleCallback() {
// 使用 requestIdleCallback 在浏览器空闲时预加载
if ("requestIdleCallback" in window) {
requestIdleCallback(() => {
this.preloadNextApp();
});
} else {
// 降级处理
setTimeout(() => {
this.preloadNextApp();
}, 100);
}
}
private async preloadNextApp() {
if (this.preloadQueue.length === 0) {
return;
}
const appName = this.preloadQueue.shift()!;
if (this.loadedApps.has(appName) || this.loadingApps.has(appName)) {
this.preloadNextApp();
return;
}
this.loadingApps.add(appName);
try {
const appConfig = this.appConfigs.find(
(config) => config.name === appName
);
if (appConfig) {
await this.preloadApp(appConfig);
this.loadedApps.add(appName);
}
} catch (error) {
console.error(`Failed to preload app ${appName}:`, error);
} finally {
this.loadingApps.delete(appName);
this.preloadNextApp();
}
}
private async preloadApp(appConfig: any) {
// 预加载应用脚本
const script = document.createElement("script");
script.src = appConfig.entry;
script.async = true;
return new Promise((resolve, reject) => {
script.onload = resolve;
script.onerror = reject;
document.head.appendChild(script);
});
}
// 添加应用到预加载队列
addToPreloadQueue(appName: string) {
if (!this.preloadQueue.includes(appName)) {
this.preloadQueue.push(appName);
}
}
// 检查应用是否已预加载
isAppPreloaded(appName: string): boolean {
return this.loadedApps.has(appName);
}
}
5.2.2 资源缓存策略
资源缓存实现:
// src/performance/ResourceCache.ts
export class ResourceCache {
private cache = new Map<string, any>();
private maxSize = 50; // 最大缓存数量
private ttl = 5 * 60 * 1000; // 5分钟过期时间
// 缓存资源
cacheResource(key: string, resource: any) {
// 如果缓存已满,删除最旧的资源
if (this.cache.size >= this.maxSize) {
const firstKey = this.cache.keys().next().value;
this.cache.delete(firstKey);
}
this.cache.set(key, {
data: resource,
timestamp: Date.now(),
});
}
// 获取缓存资源
getResource(key: string): any {
const cached = this.cache.get(key);
if (!cached) {
return null;
}
// 检查是否过期
if (Date.now() - cached.timestamp > this.ttl) {
this.cache.delete(key);
return null;
}
return cached.data;
}
// 清理过期缓存
cleanExpiredCache() {
const now = Date.now();
for (const [key, value] of this.cache.entries()) {
if (now - value.timestamp > this.ttl) {
this.cache.delete(key);
}
}
}
// 清空所有缓存
clearCache() {
this.cache.clear();
}
}
5.2.3 懒加载实现
懒加载实现:
// src/performance/LazyLoader.ts
export class LazyLoader {
private observer: IntersectionObserver;
private loadedComponents = new Set<string>();
constructor() {
this.observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const target = entry.target as HTMLElement;
const componentName = target.dataset.component;
if (componentName && !this.loadedComponents.has(componentName)) {
this.loadComponent(componentName, target);
}
}
});
},
{
rootMargin: "50px", // 提前50px开始加载
}
);
}
// 观察组件
observeComponent(element: HTMLElement, componentName: string) {
element.dataset.component = componentName;
this.observer.observe(element);
}
// 停止观察组件
unobserveComponent(element: HTMLElement) {
this.observer.unobserve(element);
}
private async loadComponent(componentName: string, container: HTMLElement) {
try {
this.loadedComponents.add(componentName);
// 动态导入组件
const component = await import(`../components/${componentName}`);
// 渲染组件
if (component.default) {
const instance = new component.default();
container.appendChild(instance.render());
}
} catch (error) {
console.error(`Failed to load component ${componentName}:`, error);
}
}
}
5.3 监控与调试
5.3.1 性能监控
性能监控实现:
// src/monitoring/PerformanceMonitor.ts
export class PerformanceMonitor {
private metrics: Map<string, any> = new Map();
private observers: PerformanceObserver[] = [];
constructor() {
this.setupPerformanceObserver();
}
private setupPerformanceObserver() {
// 监控资源加载性能
if ("PerformanceObserver" in window) {
const resourceObserver = new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
this.recordMetric("resource", {
name: entry.name,
duration: entry.duration,
size: entry.transferSize,
type: entry.initiatorType,
});
});
});
resourceObserver.observe({ entryTypes: ["resource"] });
this.observers.push(resourceObserver);
// 监控长任务
const longTaskObserver = new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
this.recordMetric("longTask", {
duration: entry.duration,
startTime: entry.startTime,
});
});
});
longTaskObserver.observe({ entryTypes: ["longtask"] });
this.observers.push(longTaskObserver);
}
}
// 记录指标
recordMetric(type: string, data: any) {
const timestamp = Date.now();
const metric = {
type,
data,
timestamp,
};
if (!this.metrics.has(type)) {
this.metrics.set(type, []);
}
this.metrics.get(type)!.push(metric);
}
// 获取性能报告
getPerformanceReport() {
const report: any = {};
for (const [type, metrics] of this.metrics.entries()) {
report[type] = {
count: metrics.length,
average: this.calculateAverage(metrics),
max: this.calculateMax(metrics),
min: this.calculateMin(metrics),
};
}
return report;
}
private calculateAverage(metrics: any[]): number {
if (metrics.length === 0) return 0;
const sum = metrics.reduce((acc, metric) => acc + metric.data.duration, 0);
return sum / metrics.length;
}
private calculateMax(metrics: any[]): number {
if (metrics.length === 0) return 0;
return Math.max(...metrics.map((metric) => metric.data.duration));
}
private calculateMin(metrics: any[]): number {
if (metrics.length === 0) return 0;
return Math.min(...metrics.map((metric) => metric.data.duration));
}
// 清理监控器
destroy() {
this.observers.forEach((observer) => observer.disconnect());
this.observers = [];
this.metrics.clear();
}
}
5.3.2 错误监控
错误监控实现:
// src/monitoring/ErrorMonitor.ts
export class ErrorMonitor {
private errors: any[] = [];
private maxErrors = 100;
constructor() {
this.setupErrorHandlers();
}
private setupErrorHandlers() {
// 全局错误处理
window.addEventListener("error", (event) => {
this.recordError({
type: "javascript",
message: event.message,
filename: event.filename,
lineno: event.lineno,
colno: event.colno,
stack: event.error?.stack,
timestamp: Date.now(),
});
});
// Promise 错误处理
window.addEventListener("unhandledrejection", (event) => {
this.recordError({
type: "promise",
message: event.reason?.message || event.reason,
stack: event.reason?.stack,
timestamp: Date.now(),
});
});
// 资源加载错误
window.addEventListener(
"error",
(event) => {
if (event.target !== window) {
this.recordError({
type: "resource",
message: `Failed to load resource: ${(event.target as any).src}`,
filename: (event.target as any).src,
timestamp: Date.now(),
});
}
},
true
);
}
// 记录错误
recordError(error: any) {
this.errors.push(error);
// 限制错误数量
if (this.errors.length > this.maxErrors) {
this.errors.shift();
}
// 发送错误到服务器
this.sendErrorToServer(error);
}
// 发送错误到服务器
private async sendErrorToServer(error: any) {
try {
await fetch("/api/errors", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
...error,
userAgent: navigator.userAgent,
url: window.location.href,
}),
});
} catch (err) {
console.error("Failed to send error to server:", err);
}
}
// 获取错误报告
getErrorReport() {
const errorTypes = this.errors.reduce((acc, error) => {
acc[error.type] = (acc[error.type] || 0) + 1;
return acc;
}, {});
return {
total: this.errors.length,
types: errorTypes,
recent: this.errors.slice(-10),
};
}
}
5.3.3 调试工具
调试工具实现:
// src/debugging/Debugger.ts
export class MicroAppDebugger {
private debugInfo: any = {};
private isDebugMode = false;
constructor() {
this.setupDebugMode();
}
private setupDebugMode() {
// 检查是否在调试模式
this.isDebugMode =
process.env.NODE_ENV === "development" ||
window.location.search.includes("debug=true");
if (this.isDebugMode) {
this.createDebugPanel();
}
}
private createDebugPanel() {
const panel = document.createElement("div");
panel.id = "micro-app-debug-panel";
panel.style.cssText = `
position: fixed;
top: 10px;
right: 10px;
width: 300px;
max-height: 500px;
background: #fff;
border: 1px solid #ccc;
border-radius: 4px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
z-index: 9999;
font-family: monospace;
font-size: 12px;
overflow-y: auto;
`;
panel.innerHTML = `
<div style="padding: 10px; border-bottom: 1px solid #eee; background: #f5f5f5;">
<strong>微前端调试面板</strong>
<button onclick="this.parentElement.parentElement.style.display='none'"
style="float: right; background: none; border: none; cursor: pointer;">×</button>
</div>
<div id="debug-content" style="padding: 10px;"></div>
`;
document.body.appendChild(panel);
this.updateDebugInfo();
}
// 更新调试信息
updateDebugInfo() {
if (!this.isDebugMode) return;
const content = document.getElementById("debug-content");
if (!content) return;
const info = {
currentApp: this.getCurrentApp(),
loadedApps: this.getLoadedApps(),
performance: this.getPerformanceInfo(),
errors: this.getErrorInfo(),
};
content.innerHTML = `
<div><strong>当前应用:</strong> ${info.currentApp || "无"}</div>
<div><strong>已加载应用:</strong> ${
info.loadedApps.join(", ") || "无"
}</div>
<div><strong>性能指标:</strong></div>
<div style="margin-left: 10px;">
<div>内存使用: ${info.performance.memory || "N/A"}</div>
<div>加载时间: ${info.performance.loadTime || "N/A"}ms</div>
</div>
<div><strong>错误信息:</strong></div>
<div style="margin-left: 10px;">
<div>错误数量: ${info.errors.count}</div>
<div>最新错误: ${info.errors.latest || "无"}</div>
</div>
`;
}
private getCurrentApp(): string | null {
return (window as any).__CURRENT_MICRO_APP__ || null;
}
private getLoadedApps(): string[] {
return (window as any).__LOADED_MICRO_APPS__ || [];
}
private getPerformanceInfo(): any {
const memory = (performance as any).memory;
return {
memory: memory
? `${Math.round(memory.usedJSHeapSize / 1024 / 1024)}MB`
: "N/A",
loadTime: performance.timing
? performance.timing.loadEventEnd - performance.timing.navigationStart
: "N/A",
};
}
private getErrorInfo(): any {
const errors = (window as any).__MICRO_APP_ERRORS__ || [];
return {
count: errors.length,
latest: errors[errors.length - 1]?.message || null,
};
}
}
5.4 内存管理优化
5.4.1 内存泄漏检测
内存泄漏检测实现:
// src/memory/MemoryLeakDetector.ts
export class MemoryLeakDetector {
private snapshots: any[] = [];
private maxSnapshots = 10;
private checkInterval = 30000; // 30秒检查一次
constructor() {
this.startMonitoring();
}
private startMonitoring() {
setInterval(() => {
this.takeSnapshot();
this.analyzeMemoryLeaks();
}, this.checkInterval);
}
private takeSnapshot() {
if ("memory" in performance) {
const memory = (performance as any).memory;
const snapshot = {
timestamp: Date.now(),
usedJSHeapSize: memory.usedJSHeapSize,
totalJSHeapSize: memory.totalJSHeapSize,
jsHeapSizeLimit: memory.jsHeapSizeLimit,
};
this.snapshots.push(snapshot);
// 限制快照数量
if (this.snapshots.length > this.maxSnapshots) {
this.snapshots.shift();
}
}
}
private analyzeMemoryLeaks() {
if (this.snapshots.length < 3) return;
const recent = this.snapshots.slice(-3);
const growth = recent[2].usedJSHeapSize - recent[0].usedJSHeapSize;
const growthRate = growth / (recent[2].timestamp - recent[0].timestamp);
// 如果内存增长超过阈值,报告潜在泄漏
if (growthRate > 1000) {
// 1KB/ms
console.warn("Potential memory leak detected:", {
growth,
growthRate,
snapshots: recent,
});
}
}
// 获取内存使用报告
getMemoryReport() {
if (this.snapshots.length === 0) {
return { message: "No memory data available" };
}
const latest = this.snapshots[this.snapshots.length - 1];
const first = this.snapshots[0];
const growth = latest.usedJSHeapSize - first.usedJSHeapSize;
return {
current: latest.usedJSHeapSize,
growth,
growthRate: growth / (latest.timestamp - first.timestamp),
snapshots: this.snapshots.length,
};
}
}
5.4.2 垃圾回收优化
垃圾回收优化实现:
// src/memory/GarbageCollectionOptimizer.ts
export class GarbageCollectionOptimizer {
private cleanupTasks: (() => void)[] = [];
private isOptimizing = false;
// 注册清理任务
registerCleanupTask(task: () => void) {
this.cleanupTasks.push(task);
}
// 执行垃圾回收优化
async optimizeGarbageCollection() {
if (this.isOptimizing) return;
this.isOptimizing = true;
try {
// 执行所有清理任务
for (const task of this.cleanupTasks) {
try {
task();
} catch (error) {
console.error("Cleanup task failed:", error);
}
}
// 清理事件监听器
this.cleanupEventListeners();
// 清理定时器
this.cleanupTimers();
// 清理 DOM 引用
this.cleanupDOMReferences();
// 强制垃圾回收(如果支持)
// 注意:gc() 不是标准的 Web API,只在特定条件下可用:
// 1. Chrome/Edge: 需要启动时添加 --js-flags="--expose-gc" 标志
// 2. Firefox: 需要设置 dom.allow_unsafe_from_into=true
// 3. 生产环境中通常不可用,主要用于开发和调试
// 4. 即使可用,也不建议在生产环境频繁调用,会影响性能
if ("gc" in window && typeof (window as any).gc === "function") {
(window as any).gc();
}
} finally {
this.isOptimizing = false;
}
}
private cleanupEventListeners() {
// 清理未使用的事件监听器
const elements = document.querySelectorAll("*");
elements.forEach((element) => {
// 这里需要根据实际情况实现事件监听器清理
// 由于无法直接获取事件监听器,这里只是示例
});
}
private cleanupTimers() {
// 清理未使用的定时器
// 注意:这里需要应用自己管理定时器 ID
const timers = (window as any).__MICRO_APP_TIMERS__ || [];
timers.forEach((timerId: number) => {
clearTimeout(timerId);
clearInterval(timerId);
});
(window as any).__MICRO_APP_TIMERS__ = [];
}
private cleanupDOMReferences() {
// 清理未使用的 DOM 引用
const elements = document.querySelectorAll("[data-micro-app]");
elements.forEach((element) => {
if (!element.isConnected) {
element.remove();
}
});
}
}
5.5 本章小结
本章深入探讨了微前端的高级特性与优化,包括:
- 沙箱机制:详细介绍了快照沙箱和代理沙箱的实现原理,以及沙箱选择策略
- 性能优化:通过预加载、资源缓存、懒加载等策略提升系统性能
- 监控与调试:实现性能监控、错误监控和调试工具,提升开发和运维效率
- 内存管理:通过内存泄漏检测和垃圾回收优化,确保系统稳定运行
这些高级特性是构建高性能、高可用微前端系统的关键,需要根据实际项目需求进行合理选择和配置。