I would make one call to the server to get a list of items. How do I make sure that only one call is made and the collections is processed only once to create a key value map.
var itemMap = {};
function getItems(){
getAllItemsFromServer().then(function(data){
data.forEach(value){
itemMap[value.key] = value;
}});
return itemMap;
}
//need to get the values from various places, using a loop here
//to make multiple calls
var itemKeys = ['a', 'b', 'c'];
itemKeys.forEach(key){
var value = getItems().then(function(data){ return data[key]});
console.log('item for key=' + value);
}
Cached Promise also allows you to manually set cache items just like you can with LRU cache, it just wraps the standard LRU . set(key, value) method with a promise.
Promise resolve() method:If the value is a promise then promise is returned. If the value has a “then” attached to the promise, then the returned promise will follow that “then” to till the final state. The promise fulfilled with its value will be returned.
It's really important to note that the Promise object doesn't return a value, it resolves a value via the then() method.
Promises lack a convenient API to safely work with data. In the section above, we looked at how the existing promise API is temptingly dangerous (using two explicit named functions vs one with anonymous parameters for each function), and how it fosters unintentionally recovering from errors.
I'm going to add a generic method for caching a promise operation. The trick here is that by treating the promise as a real proxy for a value and caching it and not the value we avoid the race condition. This also works for non promise functions just as well, illustrating how promises capture the concept of async + value well. I think it'd help you understand the problem better:
function cache(fn){
var NO_RESULT = {}; // unique, would use Symbol if ES2015-able
var res = NO_RESULT;
return function () { // if ES2015, name the function the same as fn
if(res === NO_RESULT) return (res = fn.apply(this, arguments));
return res;
};
}
This would let you cache any promise (or non promise operation very easily:
var getItems = cache(getAllItemsFromServer);
getItems();
getItems();
getItems(); // only one call was made, can `then` to get data.
Note that you cannot make it "synchronous".
I think what you're really looking for is
var cache = null; // cache for the promise
function getItems() {
return cache || (cache = getAllItemsFromServer().then(function(data){
var itemMap = {};
data.forEach(function(value){
itemMap[value.key] = value;
});
return itemMap;
}));
}
var itemKeys = ['a', 'b', 'c'];
itemKeys.forEach(function(key){
getItems().then(function(data){
return data[key];
}).then(function(value) {
console.log('item for key=' + value);
}); // notice that you get the value only asynchronously!
});
A promise is stateful, and as soon as it's fulfilled, its value cannot be changed. You can use .then
multiple times to get its contents, and you'll get the same result every time.
The getAllItemsFromServer
function returns a promise, the then
block manipulates the responses and returns the itemMap
, which is wrapped in a response (promise chaining). The promise is then cached and can be used to get the itemMap
repeatedly.
var itemsPromise = getItems(); // make the request once and get a promise
function getItems(){
return getAllItemsFromServer().then(function(data){
return data.reduce(function(itemMap, value){
itemMap[value.key] = value;
return itemMap;
}, {});
});
}
//need to get the values from various places, using a loop here
//to make multiple calls
var itemKeys = ['a', 'b', 'c'];
itemKeys.forEach(function(key){
itemsPromise.then(function(data){
return data[key];
}).then(function(value) {
console.log('item for key=' + value);
});
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With