qiankun的js隔离机制-沙箱(二)

89 阅读1分钟

代理沙箱-支持同时运行单个微应用的

class LegacySandBox {
    addedPropsMapInSandbox = new Map();
    modifiedPropsOriginalValueMapInSandbox = new Map();
    currentUpdatedPropsValueMap = 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.currentUpdatedPropsValueMap.set(prop, value);
                window[prop] = value;
            }
        });
    }
    
    active() {
        this.currentUpdatedPropsValueMap.forEach((value, prop) => this.setWindowProp(prop, value));
    }
    inactive() {
        this.modifiedPropsOriginalValueMapInSandbox.forEach((value, prop) => this.setWindowProp(prop, value));
        this.addedPropsMapInSandbox.forEach((_, prop) => this.setWindowProp(prop, undefined, true));
    }
    setWindowProp(prop, value, toDelete = false) {
        if (value === undefined && toDelete) {
            delete window[prop];
        } else {
            window[prop] = value;
        }
    }
}
// 验证:
let legacySandBox = new LegacySandBox();
legacySandBox.active();
legacySandBox.proxyWindow.city = 'jinan';
console.log('window.city-01:', window.city);   // jinan
legacySandBox.inactive();
console.log('window.city-02:', window.city);   // undefined
legacySandBox.active();
console.log('window.city-03:', window.city);   // jinan
legacySandBox.inactive();

代码摘自一篇qiankun文章,代码结构稍微做了一下调整,便于梳理。

代码解析

1.先是初始化了3个Map映射以及一个proxyWindow
2.constructor,构造函数内,先创建了一个空对象fakeWindow,然后通过new Proxy将刚才空对象以及一个handler对象作为参数传入创建了一个代理对象赋给proxyWindow
3.active激活时,遍历currentUpdatedPropsValueMap,通过下方定义的setWindowProp方法将状态更新至window
4.inactive失活时,将window状态恢复至激活之前的状态

代码执行:
1.实例化沙箱new LegacySandBox()
2.激活沙箱
3.通过沙箱的proxyWindow设置city属性,值为jinan,此时会回调Proxy的set方法,中间进行了一些逻辑判断,将值分配到对应的Map山,最终将window对象上挂上通过代理新增的属性及值
4.所以此时打印window.city为jinan
5.沙箱失活,window对象状态恢复至激活之前状态,所以打印为undefined。

下一篇会针对代理沙箱支持多个微应用同时运行的核心代码进行梳理,有兴趣的伙伴可以继续跟进。