From 2de19c46a3c570855fe1b803fe677cee0b4e4036 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sat, 20 Jan 2024 21:47:46 -0500 Subject: Improve handling of the applicationReady message (#552) --- ext/js/background/backend.js | 71 ++++++++++++++++++++++++++++++++++---------- types/ext/api.d.ts | 4 +++ types/ext/application.d.ts | 4 --- 3 files changed, 59 insertions(+), 20 deletions(-) diff --git a/ext/js/background/backend.js b/ext/js/background/backend.js index 38d82496..db7a3c0f 100644 --- a/ext/js/background/backend.js +++ b/ext/js/background/backend.js @@ -144,10 +144,13 @@ export class Backend { this._permissions = null; /** @type {PermissionsUtil} */ this._permissionsUtil = new PermissionsUtil(); + /** @type {Map void)[]>} */ + this._applicationReadyHandlers = new Map(); /* eslint-disable no-multi-spaces */ /** @type {import('api').ApiMap} */ this._apiMap = createApiMap([ + ['applicationReady', this._onApiApplicationReady.bind(this)], ['requestBackendReadySignal', this._onApiRequestBackendReadySignal.bind(this)], ['optionsGet', this._onApiOptionsGet.bind(this)], ['optionsGetFull', this._onApiOptionsGetFull.bind(this)], @@ -425,6 +428,21 @@ export class Backend { // Message handlers + /** @type {import('api').ApiHandler<'applicationReady'>} */ + _onApiApplicationReady(_params, sender) { + const {tab, frameId} = sender; + if (!tab || typeof frameId !== 'number') { return; } + const {id} = tab; + if (typeof id !== 'number') { return; } + const key = `${id}:${frameId}`; + const handlers = this._applicationReadyHandlers.get(key); + if (typeof handlers === 'undefined') { return; } + for (const handler of handlers) { + handler(); + } + this._applicationReadyHandlers.delete(key); + } + /** @type {import('api').ApiHandler<'requestBackendReadySignal'>} */ _onApiRequestBackendReadySignal(_params, sender) { // tab ID isn't set in background (e.g. browser_action) @@ -1806,18 +1824,8 @@ export class Backend { return new Promise((resolve, reject) => { /** @type {?import('core').Timeout} */ let timer = null; - /** @type {?import('extension').ChromeRuntimeOnMessageCallback} */ - let onMessage = (message, sender) => { - if ( - !sender.tab || - sender.tab.id !== tabId || - sender.frameId !== frameId || - !(typeof message === 'object' && message !== null) || - message.action !== 'applicationReady' - ) { - return; - } + const readyHandler = () => { cleanup(); resolve(); }; @@ -1826,13 +1834,10 @@ export class Backend { clearTimeout(timer); timer = null; } - if (onMessage !== null) { - chrome.runtime.onMessage.removeListener(onMessage); - onMessage = null; - } + this._removeApplicationReadyHandler(tabId, frameId, readyHandler); }; - chrome.runtime.onMessage.addListener(onMessage); + this._addApplicationReadyHandler(tabId, frameId, readyHandler); this._sendMessageTabPromise(tabId, {action: 'applicationIsReady'}, {frameId}) .then( @@ -2686,4 +2691,38 @@ export class Backend { return defaultValue; } } + + /** + * @param {number} tabId + * @param {number} frameId + * @param {() => void} handler + */ + _addApplicationReadyHandler(tabId, frameId, handler) { + const key = `${tabId}:${frameId}`; + let handlers = this._applicationReadyHandlers.get(key); + if (typeof handlers === 'undefined') { + handlers = []; + this._applicationReadyHandlers.set(key, handlers); + } + handlers.push(handler); + } + + /** + * @param {number} tabId + * @param {number} frameId + * @param {() => void} handler + * @returns {boolean} + */ + _removeApplicationReadyHandler(tabId, frameId, handler) { + const key = `${tabId}:${frameId}`; + const handlers = this._applicationReadyHandlers.get(key); + if (typeof handlers === 'undefined') { return false; } + const index = handlers.indexOf(handler); + if (index < 0) { return false; } + handlers.splice(index, 1); + if (handlers.length === 0) { + this._applicationReadyHandlers.delete(key); + } + return true; + } } diff --git a/types/ext/api.d.ts b/types/ext/api.d.ts index 3a639a9c..4f1b9026 100644 --- a/types/ext/api.d.ts +++ b/types/ext/api.d.ts @@ -112,6 +112,10 @@ export type GetTermFrequenciesDetailsTermReadingListItem = { }; type ApiSurface = { + applicationReady: { + params: void; + return: void; + }; optionsGet: { params: { optionsContext: Settings.OptionsContext; diff --git a/types/ext/application.d.ts b/types/ext/application.d.ts index 3adc53f3..903c8e45 100644 --- a/types/ext/application.d.ts +++ b/types/ext/application.d.ts @@ -46,10 +46,6 @@ export type ApiSurface = { }; return: void; }; - applicationReady: { - params: void; - return: void; - }; applicationIsReady: { params: void; return: boolean; -- cgit v1.2.3