️reduce the invocation times with next tick in sandbox to make qiankun performance in control (#1629)

This commit is contained in:
Kuitos 2021-08-04 13:05:32 +08:00 committed by GitHub
parent 9e4274e3f8
commit d7e96a02ae
4 changed files with 38 additions and 7 deletions

View File

@ -3,6 +3,7 @@ import {
getDefaultTplWrapper, getDefaultTplWrapper,
getWrapperId, getWrapperId,
getXPathForElement, getXPathForElement,
nextTask,
sleep, sleep,
validateExportLifecycle, validateExportLifecycle,
} from '../utils'; } from '../utils';
@ -116,3 +117,20 @@ test('should getXPathForElement work well', () => {
const xpath1 = getXPathForElement(virtualDOM, document); const xpath1 = getXPathForElement(virtualDOM, document);
expect(xpath1).toBeUndefined(); expect(xpath1).toBeUndefined();
}); });
it('should nextTick just executed once in one task context', async () => {
let counter = 0;
nextTask(() => ++counter);
nextTask(() => ++counter);
nextTask(() => ++counter);
nextTask(() => ++counter);
await sleep(0);
expect(counter).toBe(1);
await sleep(0);
nextTask(() => ++counter);
await sleep(0);
nextTask(() => ++counter);
await sleep(0);
expect(counter).toBe(3);
});

View File

@ -11,6 +11,7 @@ declare global {
__POWERED_BY_QIANKUN__?: boolean; __POWERED_BY_QIANKUN__?: boolean;
__INJECTED_PUBLIC_PATH_BY_QIANKUN__?: string; __INJECTED_PUBLIC_PATH_BY_QIANKUN__?: string;
__QIANKUN_DEVELOPMENT__?: boolean; __QIANKUN_DEVELOPMENT__?: boolean;
Zone?: CallableFunction;
} }
} }

View File

@ -5,7 +5,7 @@
*/ */
import type { SandBox } from '../interfaces'; import type { SandBox } from '../interfaces';
import { SandBoxType } from '../interfaces'; import { SandBoxType } from '../interfaces';
import { nextTick } from '../utils'; import { nextTask } from '../utils';
import { getTargetValue, setCurrentRunningSandboxProxy } from './common'; import { getTargetValue, setCurrentRunningSandboxProxy } from './common';
/** /**
@ -215,13 +215,13 @@ export default class ProxySandbox implements SandBox {
}, },
get(target: FakeWindow, p: PropertyKey): any { get(target: FakeWindow, p: PropertyKey): any {
if (p === Symbol.unscopables) return unscopables;
setCurrentRunningSandboxProxy(proxy); setCurrentRunningSandboxProxy(proxy);
// FIXME if you have any other good ideas // FIXME if you have any other good ideas
// remove the mark in next tick, thus we can identify whether it in micro app or not // 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 complex cases, such as the micro app runs in the same task context with master in some case // this approach is just a workaround, it could not cover all complex cases, such as the micro app runs in the same task context with master in some case
nextTick(() => setCurrentRunningSandboxProxy(null)); nextTask(() => setCurrentRunningSandboxProxy(null));
if (p === Symbol.unscopables) return unscopables;
// avoid who using window.window or window.self to escape the sandbox environment to touch the really window // avoid who using window.window or window.self to escape the sandbox environment to touch the really window
// see https://github.com/eligrey/FileSaver.js/blob/master/src/FileSaver.js#L13 // see https://github.com/eligrey/FileSaver.js/blob/master/src/FileSaver.js#L13

View File

@ -14,12 +14,24 @@ export function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms)); return new Promise((resolve) => setTimeout(resolve, ms));
} }
// Promise.then might be synchronized in Zone.js context, we need to use setTimeout instead to mock next tick.
const nextTick: (cb: () => void) => void =
typeof window.Zone === 'function' ? setTimeout : (cb) => Promise.resolve().then(cb);
let globalTaskPending = false;
/** /**
* run a callback after next tick * Run a callback before next task executing, and the invocation is idempotent in every singular task
* That means even we called nextTask multi times in one task, only the first callback will be pushed to nextTick to be invoked.
* @param cb * @param cb
*/ */
export function nextTick(cb: () => void): void { export function nextTask(cb: () => void): void {
Promise.resolve().then(cb); if (!globalTaskPending) {
globalTaskPending = true;
nextTick(() => {
cb();
globalTaskPending = false;
});
}
} }
const fnRegexCheckCacheMap = new WeakMap<any | FunctionConstructor, boolean>(); const fnRegexCheckCacheMap = new WeakMap<any | FunctionConstructor, boolean>();