原理:和快照沙箱原理相同,是对快照沙箱的完善。不同是LegacySandBox
使用es6的proxy
,使用代理可以不用直接修改window上的属性,卸载时可以直接卸载不用遍历所有window上的属性进行对比再卸载
缺点:多个子应用还是会写在window上会相互影响,只支持同时运行一个子应用,多应用解决方案,使用ProxySandBox
简易版实现:
//获取属性是否可配置
function isConfigurable(target, prop) {
const descriptors = Object.getOwnPropertyDescriptor(target, prop);
return descriptors ? descriptors.configurable : true;
}
//设置属性
function setWindowProp(prop, value, toDelete) {
if (value === undefined && toDelete) {
delete window[prop];
} else if (isConfigurable(window, prop) && typeof prop !== "symbol") {
Object.defineProperty(window, prop, {
writable: true,
configurable: true,
});
window[prop] = value;
}
}
//代理实现
class LegacySandbox {
addedPropsMapInSandbox = new Map(); //存放新增的全局变量,用于卸载时重置属性
modifiedPropsOriginalValueMapInSandbox = new Map(); //存放修改的全局变量
currentUpdatedPropsValueMap = new Map(); //存放运行期的所有变量
sandboxRunning = true;
proxy = null;
active() {
//新增时注册变量
this.currentUpdatedPropsValueMap.forEach((value, prop) =>
setWindowProp(prop, value)
);
this.sandboxRunning = true;
}
inactive() {
this.modifiedPropsOriginalValueMapInSandbox.forEach((v, p) =>
setWindowProp(p, v)
);
this.addedPropsMapInSandbox.forEach((_, p) =>
setWindowProp(p, undefined, true)
);
this.sandboxRunning = false;
}
constructor() {
const fakeWindow = Object.create(null);
//把window上的属性都代理到fakeWindow上,使用proxy不用每次都遍历所有window上的属性
this.proxy = new Proxy(fakeWindow, {
set: (target, propKey, value, receiver) => {
//获取window上的属性
const originalValue = window[propKey];
//window上不存在这个新增的属性,记录到addedPropsMapInSandbox
if (!window.hasOwnProperty(propKey)) {
this.addedPropsMapInSandbox.set(propKey, value);
} else if (!this.modifiedPropsOriginalValueMapInSandbox.has(propKey)) {
//window上存在这个属性了,说明是更新,记录到modifiedPropsOriginalValueMapInSandbox
this.modifiedPropsOriginalValueMapInSandbox.set(
propKey,
originalValue
);
}
//当前活动的属性,记录到currentUpdatedPropsValueMap
this.currentUpdatedPropsValueMap.set(propKey, value);
window[propKey] = value;
},
get: (target, propKey, receiver) => {
return target[propKey];
},
});
}
}
let legacySandBox = new LegacySandbox();
legacySandBox.active();
legacySandBox.proxy.app = "vue2";
console.log("window.app-01:", window.app);
legacySandBox.inactive();
console.log("window.app-02:", window.app);
legacySandBox.active();
console.log("window.app-03:", window.app);
legacySandBox.inactive();
网友评论