Skip to content

js执行沙箱

创建一个顶层对象(proxy),作为子应用执行js代码时的顶层对象; 隔离不同子应用执行的js代码(js运行环境隔离)

ProxySandbox 代理沙箱

非IE默认使用此沙箱。ProxySandbox会返回一个代理到window对象的Proxy提供给子应用使用

  • 在qiankun中,proxy对象会被在eval+with作为全局对象使用
js
// js 代理沙箱 基本实现
class ProxySandbox {
  constructor() {
    const rawWindow = window
    const proxyWindow = {}
    this.proxy = new Proxy(proxyWindow, {
      get(target, key) { // target为第一个参数(代理对象proxyWindow)
        return target[key] || window[key]
      },
      set(target, key, value) {
        target[key] = value
        return true
      }
    })
  }
}
const ProxySandbox1 = new ProxySandbox()
const ProxySandbox2 = new ProxySandbox()
window.a = 1;
// 沙箱1
((window) => {
  window.a = 2
})(ProxySandbox1.proxy);

// 沙箱2
((window) => {
  window.a = 3
})(ProxySandbox1.proxy)

// 代理沙箱,互不影响window
console.log(window.a) // 1

SnapshotSandbox 快照沙箱(单例)

不支持Proxy语法则使用此沙箱。

  • 基本思路: 把window对象拷贝给一个新对象缓存下来(快照一份),在退出的时候比对下原快照,然后把修改过的属性通过一个 modifyPropsMap 变量存起来,然后通过快照还原window

WARNING

快照沙箱不支持多实例(多个子应用)同时运行,window对象快照会出问题.

js
// js 快照沙箱 基本实现
class SnapshotSandbox {
  constructor() {
    this.proxy = window
    this.modifyPropsMap = {} // 记录被修改的属性
    // this.active()
  }
  // 激活沙箱
  active() {
    this.windowSnapshot = {} // 用于存放激活时window的快照【每次激活需要清空一次, 否则可能遗留上次多余的属性】
    for (const key in window) {
      if (window.hasOwnProperty(key)) {
        this.windowSnapshot[key] = window[key] // 把window上的属性快照一份
      }
    }
    // 激活时如果发现原来有被更改过的属性,则重新赋值回来
    for (const key in this.modifyPropsMap) {
      window[key] = this.modifyPropsMap[key]
    }
  }

  // 沙箱失活(切换沙箱)
  inactive() {
    for (const key in window) {
      if (window.hasOwnProperty(key)) {
        if (window[key] !== this.windowSnapshot[key]) { // 如果window的某项属性不等于原来快照的属性
          this.modifyPropsMap[key] = window[key] // 则保存被更改过的属性
          window[key] = this.windowSnapshot[key] // 还原window激活时的属性
        }
      }
    }
  }
}

// 1号沙箱
const Sandbox1 = new SnapshotSandbox(); // 这个分号不能少,否则自调用函数(IIFE)报语法错误

Sandbox1.active() // 激活, 快照window属性
window.a = 1 // 新增属性
console.log(window.a) // 1

Sandbox1.inactive() // 失活, 还原window
console.log(window.a) // undefined

Sandbox1.active() // 再激活试试
console.log(window.a) // 1

Sandbox1.inactive() // 失活, 还原window,尝试使用2号沙箱

LegacySandbox 代理沙箱(单例|已弃用)

未深入探究