diff --git a/src/sandbox/__tests__/proxySandbox.test.ts b/src/sandbox/__tests__/proxySandbox.test.ts index 769b3eb..22618fd 100644 --- a/src/sandbox/__tests__/proxySandbox.test.ts +++ b/src/sandbox/__tests__/proxySandbox.test.ts @@ -4,7 +4,7 @@ */ import { isBoundedFunction } from '../../utils'; -import { attachDocProxySymbol } from '../common'; +import { documentAttachProxyMap } from '../common'; import ProxySandbox from '../proxySandbox'; beforeAll(() => { @@ -206,9 +206,9 @@ test('document accessing should modify the attachDocProxySymbol value every time const proxy2 = new ProxySandbox('doc-access-test2').proxy; const d1 = proxy1.document; - expect(d1[attachDocProxySymbol]).toBe(proxy1); + expect(documentAttachProxyMap.get(d1)).toBe(proxy1); const d2 = proxy2.document; - expect(d2[attachDocProxySymbol]).toBe(proxy2); + expect(documentAttachProxyMap.get(d2)).toBe(proxy2); expect(d1).toBe(d2); expect(d1).toBe(document); @@ -217,10 +217,10 @@ test('document accessing should modify the attachDocProxySymbol value every time test('document attachDocProxySymbol mark should be remove before next tasl', done => { const { proxy } = new ProxySandbox('doc-symbol'); const d1 = proxy.document; - expect(d1[attachDocProxySymbol]).toBe(proxy); + expect(documentAttachProxyMap.get(d1)).toBe(proxy); setTimeout(() => { - expect(d1[attachDocProxySymbol]).toBeUndefined(); + expect(documentAttachProxyMap.get(d1)).toBeUndefined(); done(); }); }); diff --git a/src/sandbox/common.ts b/src/sandbox/common.ts index 909198c..068d660 100644 --- a/src/sandbox/common.ts +++ b/src/sandbox/common.ts @@ -5,24 +5,18 @@ import { isBoundedFunction, isCallable, isConstructable } from '../utils'; -export const attachDocProxySymbol = Symbol('attach-proxy-container'); - -declare global { - interface Document { - [attachDocProxySymbol]: WindowProxy; - } -} - -const boundValueSymbol = Symbol('bound value'); +export const documentAttachProxyMap = new WeakMap(); +const functionBoundedValueMap = new WeakMap(); export function getTargetValue(target: any, value: any): any { /* 仅绑定 isCallable && !isBoundedFunction && !isConstructable 的函数对象,如 window.console、window.atob 这类。目前没有完美的检测方式,这里通过 prototype 中是否还有可枚举的拓展方法的方式来判断 @warning 这里不要随意替换成别的判断方式,因为可能触发一些 edge case(比如在 lodash.isFunction 在 iframe 上下文中可能由于调用了 top window 对象触发的安全异常) */ if (isCallable(value) && !isBoundedFunction(value) && !isConstructable(value)) { - if (value[boundValueSymbol]) { - return value[boundValueSymbol]; + const cachedBoundValue = functionBoundedValueMap.get(value); + if (cachedBoundValue) { + return cachedBoundValue; } const boundValue = value.bind(target); @@ -35,7 +29,7 @@ export function getTargetValue(target: any, value: any): any { // copy prototype, for performance reason, we use in operator to check rather than hasOwnProperty if ('prototype' in value) boundValue.prototype = value.prototype; - Object.defineProperty(value, boundValueSymbol, { enumerable: false, value: boundValue }); + functionBoundedValueMap.set(value, boundValue); return boundValue; } diff --git a/src/sandbox/patchers/dynamicAppend/forStrictSandbox.ts b/src/sandbox/patchers/dynamicAppend/forStrictSandbox.ts index ec2e082..b2605eb 100644 --- a/src/sandbox/patchers/dynamicAppend/forStrictSandbox.ts +++ b/src/sandbox/patchers/dynamicAppend/forStrictSandbox.ts @@ -4,7 +4,7 @@ */ import { Freer } from '../../../interfaces'; -import { attachDocProxySymbol } from '../../common'; +import { documentAttachProxyMap } from '../../common'; import { ContainerConfig, isHijackingTag, @@ -27,9 +27,12 @@ function patchDocumentCreateElement() { ): HTMLElement { const element = rawDocumentCreateElement.call(this, tagName, options); if (isHijackingTag(tagName)) { - const proxyContainerConfig = proxyAttachContainerConfigMap.get(this[attachDocProxySymbol]); - if (proxyContainerConfig) { - elementAttachContainerConfigMap.set(element, proxyContainerConfig); + const attachProxy = documentAttachProxyMap.get(this); + if (attachProxy) { + const proxyContainerConfig = proxyAttachContainerConfigMap.get(attachProxy); + if (proxyContainerConfig) { + elementAttachContainerConfigMap.set(element, proxyContainerConfig); + } } } diff --git a/src/sandbox/proxySandbox.ts b/src/sandbox/proxySandbox.ts index d337370..6e0e8c5 100644 --- a/src/sandbox/proxySandbox.ts +++ b/src/sandbox/proxySandbox.ts @@ -5,7 +5,7 @@ */ import { SandBox, SandBoxType } from '../interfaces'; import { nextTick } from '../utils'; -import { attachDocProxySymbol, getTargetValue } from './common'; +import { documentAttachProxyMap, getTargetValue } from './common'; /** * fastest(at most time) unique array method @@ -224,11 +224,11 @@ export default class ProxySandbox implements SandBox { // mark the symbol to document while accessing as document.createElement could know is invoked by which sandbox for dynamic append patcher if (p === 'document') { - document[attachDocProxySymbol] = proxy; + documentAttachProxyMap.set(document, proxy); // remove the mark in next tick, thus we can identify whether it in micro app or not // this approach is just a workaround, it could not cover all the complex scenarios, such as the micro app runs in the same task context with master in som case // fixme if you have any other good ideas - nextTick(() => delete document[attachDocProxySymbol]); + nextTick(() => documentAttachProxyMap.delete(document)); return document; }