diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /devtools/client/memory/actions/task-cache.js | |
parent | Initial commit. (diff) | |
download | firefox-esr-upstream.tar.xz firefox-esr-upstream.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'devtools/client/memory/actions/task-cache.js')
-rw-r--r-- | devtools/client/memory/actions/task-cache.js | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/devtools/client/memory/actions/task-cache.js b/devtools/client/memory/actions/task-cache.js new file mode 100644 index 0000000000..c472cb69da --- /dev/null +++ b/devtools/client/memory/actions/task-cache.js @@ -0,0 +1,105 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ +"use strict"; + +const { assert } = require("resource://devtools/shared/DevToolsUtils.js"); + +/** + * The `TaskCache` allows for re-using active tasks when spawning a second task + * would simply duplicate work and is unnecessary. It maps from a task's unique + * key to the promise of its result. + */ +const TaskCache = (module.exports = class TaskCache { + constructor() { + this._cache = new Map(); + } + + /** + * Get the promise keyed by the given unique `key`, if one exists. + * + * @param {Any} key + * @returns {Promise<Any> | undefined} + */ + get(key) { + return this._cache.get(key); + } + + /** + * Put the task result promise in the cache and associate it with the given + * `key` which must not already have an entry in the cache. + * + * @param {Any} key + * @param {Promise<Any>} promise + */ + put(key, promise) { + assert(!this._cache.has(key), "We should not override extant entries"); + + this._cache.set(key, promise); + } + + /** + * Remove the cache entry with the given key. + * + * @param {Any} key + */ + remove(key) { + assert( + this._cache.has(key), + `Should have an extant entry for key = ${key}` + ); + + this._cache.delete(key); + } +}); + +/** + * Create a new action-orchestrating task that is automatically cached. The + * tasks themselves are responsible from removing themselves from the cache. + * + * @param {Function(...args) -> Any} getCacheKey + * @param {Generator(...args) -> Any} task + * + * @returns Cacheable, Action-Creating Task + */ +TaskCache.declareCacheableTask = function ({ getCacheKey, task }) { + const cache = new TaskCache(); + + return function (...args) { + return async function ({ dispatch, getState }) { + const key = getCacheKey(...args); + + const extantResult = cache.get(key); + if (extantResult) { + return extantResult; + } + + // Ensure that we have our new entry in the cache *before* dispatching the + // task! + let resolve; + cache.put( + key, + new Promise(r => { + resolve = r; + }) + ); + + resolve( + dispatch(async function () { + try { + args.push(() => cache.remove(key), dispatch, getState); + return await task(...args); + } catch (error) { + // Don't perma-cache errors. + if (cache.get(key)) { + cache.remove(key); + } + throw error; + } + }) + ); + + return cache.get(key); + }; + }; +}; |