refactor: use WeakRef on main process side of remote (#24115)
This commit is contained in:
parent
09c0ee8f87
commit
e1e73fa5f5
9 changed files with 43 additions and 181 deletions
|
@ -14,16 +14,48 @@ if (!features.isRemoteModuleEnabled()) {
|
|||
throw new Error('remote module is disabled');
|
||||
}
|
||||
|
||||
const hasProp = {}.hasOwnProperty;
|
||||
|
||||
// The internal properties of Function.
|
||||
const FUNCTION_PROPERTIES = [
|
||||
'length', 'name', 'arguments', 'caller', 'prototype'
|
||||
];
|
||||
|
||||
type RendererFunctionId = [string, number] // [contextId, funcId]
|
||||
type FinalizerInfo = { id: RendererFunctionId, webContents: electron.WebContents, frameId: number };
|
||||
type WeakRef<T> = { deref(): T | undefined }
|
||||
type CallIntoRenderer = (...args: any[]) => void
|
||||
|
||||
// The remote functions in renderer processes.
|
||||
// id => Function
|
||||
const rendererFunctions = v8Util.createDoubleIDWeakMap<(...args: any[]) => void>();
|
||||
const rendererFunctionCache = new Map<string, WeakRef<CallIntoRenderer>>();
|
||||
// eslint-disable-next-line no-undef
|
||||
const finalizationRegistry = new (globalThis as any).FinalizationRegistry((fi: FinalizerInfo) => {
|
||||
const mapKey = fi.id[0] + '~' + fi.id[1];
|
||||
const ref = rendererFunctionCache.get(mapKey);
|
||||
if (ref !== undefined && ref.deref() === undefined) {
|
||||
rendererFunctionCache.delete(mapKey);
|
||||
if (!fi.webContents.isDestroyed()) { fi.webContents.sendToFrame(fi.frameId, 'ELECTRON_RENDERER_RELEASE_CALLBACK', fi.id[0], fi.id[1]); }
|
||||
}
|
||||
});
|
||||
|
||||
function getCachedRendererFunction (id: RendererFunctionId): CallIntoRenderer | undefined {
|
||||
const mapKey = id[0] + '~' + id[1];
|
||||
const ref = rendererFunctionCache.get(mapKey);
|
||||
if (ref !== undefined) {
|
||||
const deref = ref.deref();
|
||||
if (deref !== undefined) return deref;
|
||||
}
|
||||
}
|
||||
function setCachedRendererFunction (id: RendererFunctionId, wc: electron.WebContents, frameId: number, value: CallIntoRenderer) {
|
||||
// eslint-disable-next-line no-undef
|
||||
const wr = new (globalThis as any).WeakRef(value) as WeakRef<CallIntoRenderer>;
|
||||
const mapKey = id[0] + '~' + id[1];
|
||||
rendererFunctionCache.set(mapKey, wr);
|
||||
finalizationRegistry.register(value, {
|
||||
id,
|
||||
webContents: wc,
|
||||
frameId
|
||||
} as FinalizerInfo);
|
||||
return value;
|
||||
}
|
||||
|
||||
// Return the description of object's members:
|
||||
const getObjectMembers = function (object: any): ObjectMember[] {
|
||||
|
@ -80,7 +112,7 @@ const valueToMeta = function (sender: electron.WebContents, contextId: string, v
|
|||
type = 'value';
|
||||
} else if (isPromise(value)) {
|
||||
type = 'promise';
|
||||
} else if (hasProp.call(value, 'callee') && value.length != null) {
|
||||
} else if (Object.prototype.hasOwnProperty.call(value, 'callee') && value.length != null) {
|
||||
// Treat the arguments object as array.
|
||||
type = 'array';
|
||||
} else if (optimizeSimpleObject && v8Util.getHiddenValue(value, 'simple')) {
|
||||
|
@ -226,9 +258,8 @@ const unwrapArgs = function (sender: electron.WebContents, frameId: number, cont
|
|||
const objectId: [string, number] = [contextId, meta.id];
|
||||
|
||||
// Cache the callbacks in renderer.
|
||||
if (rendererFunctions.has(objectId)) {
|
||||
return rendererFunctions.get(objectId);
|
||||
}
|
||||
const cachedFunction = getCachedRendererFunction(objectId);
|
||||
if (cachedFunction !== undefined) { return cachedFunction; }
|
||||
|
||||
const callIntoRenderer = function (this: any, ...args: any[]) {
|
||||
let succeed = false;
|
||||
|
@ -242,8 +273,7 @@ const unwrapArgs = function (sender: electron.WebContents, frameId: number, cont
|
|||
v8Util.setHiddenValue(callIntoRenderer, 'location', meta.location);
|
||||
Object.defineProperty(callIntoRenderer, 'length', { value: meta.length });
|
||||
|
||||
v8Util.setRemoteCallbackFreer(callIntoRenderer, frameId, contextId, meta.id, sender);
|
||||
rendererFunctions.set(objectId, callIntoRenderer);
|
||||
setCachedRendererFunction(objectId, sender, frameId, callIntoRenderer);
|
||||
return callIntoRenderer;
|
||||
}
|
||||
default:
|
||||
|
@ -308,11 +338,12 @@ const logStack = function (contents: electron.WebContents, code: string, stack:
|
|||
|
||||
handleRemoteCommand('ELECTRON_BROWSER_WRONG_CONTEXT_ERROR', function (event, contextId, passedContextId, id) {
|
||||
const objectId: [string, number] = [passedContextId, id];
|
||||
if (!rendererFunctions.has(objectId)) {
|
||||
const cachedFunction = getCachedRendererFunction(objectId);
|
||||
if (cachedFunction === undefined) {
|
||||
// Do nothing if the error has already been reported before.
|
||||
return;
|
||||
}
|
||||
removeRemoteListenersAndLogWarning(event.sender, rendererFunctions.get(objectId)!);
|
||||
removeRemoteListenersAndLogWarning(event.sender, cachedFunction);
|
||||
});
|
||||
|
||||
handleRemoteCommand('ELECTRON_BROWSER_REQUIRE', function (event, contextId, moduleName, stack) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue