mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-28 13:21:28 +00:00

In short, thunk actions are changing from a signature with 2 parameters (dispatch and getState): `(dispatch, getState)`, to an object that contains those properties: `({ dispatch, getState })`. This is done so we can merge thunk and thunk-with-options Differential Revision: https://phabricator.services.mozilla.com/D92888
106 lines
2.6 KiB
JavaScript
106 lines
2.6 KiB
JavaScript
/* 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("devtools/shared/DevToolsUtils");
|
|
|
|
/**
|
|
* 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);
|
|
};
|
|
};
|
|
};
|