乾坤微前端js沙箱机制

本文介绍了三种沙箱技术:快照沙箱通过保存和还原window属性处理微应用间的切换;LegacySandbox更注重性能,但限制了多应用同时运行;ProxySandbox支持多应用同时活跃但受限于浏览器兼容性。
摘要由CSDN通过智能技术生成

1 快照沙箱

  1. modifyPropsMap对象存储子应用的属性; windowSnapshot对象存储微应用未加载时的window对象属性;
  2. 进入微应用,利用windowSnapshot对象存储window对象的属性; 并将window对象的属性替换为modifyPropsMap对象的属性;
  3. 离开微应用:modifyPropsMap对象属性同步window对象属性; window对象属性还原为 windowSnapshot对象属性;

缺点:

  • 不支持多个微应用同时处于运行状态;
  • 遍历window对象上的所有属性,性能差;
    优点:
  • 适用于所有浏览器;
class SanapshotSandbox {
  windowSnapshot = {};
  modifyPropsMap = {};

  // 进入微应用
  active() {
    // 保存window对象上所有属性的状态
    for (const prop in window) {
      this.windowSnapshot[prop] = window[prop];
    }

    // 恢复上一次在运行该微应用的时候修改过的window上的属性
    Object.keys(this.modifyPropsMap).forEach(prop => {
      window[prop] = this.modifyPropsMap[prop];
    });
  }

  // 离开微应用
  inactive() {
    for (const prop in window) {
      if (window[prop] !== this.windowSnapshot[prop]) {
        // 记录修改了window上的哪些属性
        this.modifyPropsMap[prop] = window[prop];
        // 将window上的属性状态还原至微应用运行之前的状态
        window[prop] = this.windowSnapshot[prop];
      }
    }
  }
}
window.city = 'Beijing';
let snapshotSanbox = new SanapshotSandbox();
console.log('====>window.city 01:', window.city);
snapshotSanbox.active();
window.city = 'Shanghai';
console.log('====>window.city 02:', window.city);
snapshotSanbox.inactive();
console.log('====>window.city 03:', window.city);

snapshotSanbox.active();
console.log('====>window.city 04:', window.city);

// ====>window.city 01: Beijing
// ====>window.city 02: Shanghai
// ====>window.city 03: Beijing
// ====>window.city 04: Shanghai

2 LegacySandbox沙箱

优点:

  • 不需要遍历window上所有的属性,性能良好;

缺点:

  • 同一时间只能激活一个微应用;
class LegacySandbox {
  modifiedPropsOriginalValueMapInSandbox = new Map(); // 修改属性
  addedPropsMapInSandbox = new Map(); // 新增的属性
  currentUpdatePropsValueMap = new Map(); // 所有变化的属性,包括修改的属性和新增的属性
  proxyWindow = {}; // 代理对象
 
  constructor() {
    const fakeWindow = Object.create(null);
    this.proxyWindow = new Proxy(fakeWindow, {
      set: (target, prop, value, receiver) => {
        const originalVal = window[prop];
        if (!window.hasOwnProperty(prop)) {
          this.addedPropsMapInSandbox.set(prop, value);
        } else if (!this.modifiedPropsOriginalValueMapInSandbox.has(prop)) {
          this.modifiedPropsOriginalValueMapInSandbox.set(prop, originalVal);
        }
        this.currentUpdatePropsValueMap.set(prop, value);
        window[prop] = value;
      },

      get: (target, prop, receiver) => {
        return window[prop];
      }
    })
  }

  setWindowProp(prop, value, isToDelete) {
    if (value === undefined && isToDelete) {
      delete window[prop];
    } else {
      window[prop] = value;
    }
  }

  active() {
    // 恢复上一次该微应用处于运行状态时,对window上做的所有修改
    this.currentUpdatePropsValueMap.forEach((value, prop) => {
      this.setWindowProp(prop, value);
    })
  }

  inactive() {
    // 还原window上原有的属性
    this.modifiedPropsOriginalValueMapInSandbox.forEach((value, prop) => {
      this.setWindowProp(prop, value);
    });

    // 删除在微应用运行期间,window上新增的属性
    this.addedPropsMapInSandbox.forEach((_, prop) => {
      this.setWindowProp(prop.undefined, true);
    })
  }
}
window.city = 'Beijing';
let legacySandbox = new LegacySandbox();
console.log('====>window.city 01:', window.city);
legacySandbox.active();
legacySandbox.proxyWindow.city = 'Shanghai';
console.log('====>window.city 02:', window.city);
legacySandbox.inactive();
console.log('====>window.city 03:', window.city);

legacySandbox.active();
console.log('====>window.city 04:', window.city);


// ====>window.city 01: Beijing
// ====>window.city 02: Shanghai
// ====>window.city 03: Beijing
// ====>window.city 04: Shanghai

3 ProxySandbox

优点:

  • 不需要遍历window上的所有属性,性能良好;
  • 同一时间可以激活多个微应用;
    缺点:
  • 只适用于支持 ES6语法 的浏览器(IE7-IE11不支持ES6);

使用工具如 Babel 将使用了 ES6+ 语法(包括 Proxy)的源代码转换为这些老旧浏览器能够理解的 ES5 或更低版本的 JavaScript 代码。Babel 可以通过配置相应的转译插件(如 @babel/plugin-transform-proxy)来尝试模拟 Proxy 行为,但这通常只能实现部分功能,并且性能和兼容性可能不如原生 Proxy

class ProxySandbox {
  proxyWindow = {};
  isRunning = false;

  constructor() {
    const fakeWindow = Object.create(null);
    this.proxyWindow = new Proxy(fakeWindow, {
      set: (target, prop, value, receiver) => {
        if(this.isRunning) {
          target[prop] = value;
        }
      },
      get: (target, prop, receiver) => {
        return prop in target ? target[prop]: window[prop];
      },
    });
  }
  active() {
    this.isRunning = true;
  }

  inactive() {
    this.isRunning = false;
  }
}
window.city = 'Beijing';
let proxtSandbox01 = new ProxySandbox();
let proxtSandbox02 = new ProxySandbox();
proxtSandbox01.active();
proxtSandbox02.active();
proxtSandbox01.proxyWindow.city = 'Shanghai';
proxtSandbox02.proxyWindow.city = 'Chendu';
console.log('====>proxtSandbox01.proxyWindow.city 01:', proxtSandbox01.proxyWindow.city);
console.log('====>proxtSandbox02.proxyWindow.city 01:', proxtSandbox02.proxyWindow.city);
console.log('====>window.city 01:', window.city);
proxtSandbox01.inactive();
proxtSandbox02.inactive();
console.log('====>proxtSandbox01.proxyWindow.city 02:', proxtSandbox01.proxyWindow.city);
console.log('====>proxtSandbox02.proxyWindow.city 02:', proxtSandbox02.proxyWindow.city);
console.log('====>window.city 02:', window.city);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值