Best Es6 Way To Get Name Based Results With Promise.all
Solution 1:
ES6 supports destructuring, so if you just want to name the results you can write:
varmyFuncAsync1 = () => Promise.resolve(1);
varmyFuncAsync2 = () => Promise.resolve(2);
Promise.all([myFuncAsync1(), myFuncAsync2()])
.then(([result1, result2]) =>console.log(result1 +" and "+ result2)) //1 and 2
.catch(e =>console.error(e));
Works in Firefox and Chrome now.
Solution 2:
Is this the kind of thing?
var promises = [];
promises.push(myFuncAsync1().then(r => ({name : "func1", result : r})));
promises.push(myFuncAsync1().then(r => ({name : "func2", result : r})));
Promise.all(promises).then(results => {
var lookup = results.reduce((prev, curr) => {
prev[curr.name] = curr.result;
return prev;
}, {});
var firstResult = lookup["func1"];
var secondResult = lookup["func2"];
}
Solution 3:
If you don't want to modify the format of result objects, here is a helper function that allows assigning a name to each entry to access it later.
constallNamed = (nameToPromise) => {
const entries = Object.entries(nameToPromise);
returnPromise.all(entries.map(e => e[1]))
.then(results => {
const nameToResult = {};
for (let i = 0; i < results.length; ++i) {
const name = entries[i][0];
nameToResult[name] = results[i];
}
return nameToResult;
});
};
Usage:
var lookup = awaitallNamed({
rootStatus: fetch('https://stackoverflow.com/').then(rs => rs.status),
badRouteStatus: fetch('https://stackoverflow.com/badRoute').then(rs => rs.status),
});
var firstResult = lookup.rootStatus; // = 200var secondResult = lookup.badRouteStatus; // = 404
If you are using typescript you can even specify relationship between input keys and results using keyof
construct:
type ThenArg<T> = T extendsPromiseLike<infer U> ? U : T;
exportconst allNamed = <
T extendsRecord<string, Promise<any>>,
TResolved extends {[P in keyof T]: ThenArg<T[P]>}
>(nameToPromise: T): Promise<TResolved> => {
const entries = Object.entries(nameToPromise);
returnPromise.all(entries.map(e => e[1]))
.then(results => {
constnameToResult: TResolved = <any>{};
for (let i = 0; i < results.length; ++i) {
constname: keyof T = entries[i][0];
nameToResult[name] = results[i];
}
return nameToResult;
});
};
Solution 4:
A great solution for this is to use async await. Not exactly ES6 like you asked, but ES8! But since Babel supports it fully, here we go:
You can avoid using only the array index by using async
/await
as follows.
This async
function allows you to literally halt your code inside of it by allowing you to use the await
keyword inside of the function, placing it before a promise. As as an async
function encounters await
on a promise that hasn't yet been resolved, the function immediately returns a pending promise. This returned promise resolves as soon as the function actually finishes later on. The function will only resume when the previously awaited promise is resolved, during which it will resolve the entire await Promise
statement to the return value of that Promise, allowing you to put it inside of a variable. This effectively allows you to halt your code without blocking the thread. It's a great way to handle asynchronous stuff in JavaScript in general, because it makes your code more chronological and therefore easier to reason about:
asyncfunctionresolvePromiseObject(promiseObject) {
awaitPromise.all(Object.values(promiseObject));
const ret = {};
for ([key, value] ofObject.entries(promiseObject)) {
// All these resolve instantly due to the previous await
ret[key] = await value;
};
return ret;
}
As with anything above ES5: Please make sure that Babel is configured correctly so that users on older browsers can run your code without issue. You can make async await work flawlessly on even IE11, as long as your babel configuration is right.
Solution 5:
in regards to @kragovip's answer, the reason you want to avoid that is shown here:
"...it’s really easy to get used to await all of your network and I/O calls.
However, you should be careful when using it multiple times in a row as the await keyword stops execution of all the code after it. (Exactly as it would be in synchronous code)"
Bad Example (DONT FOLLOW)
async function processData() {
const data1 = await downloadFromService1();
const data2 = await downloadFromService2();
const data3 = await downloadFromService3();
...
}
"There is also absolutely no need to wait for the completion of first request as none of other requests depend on its result.
We would like to have requests sent in parallel and wait for all of them to finish simultaneously. This is where the power of asynchronous event-driven programming lies.
To fix this we can use Promise.all() method. We save Promises from async function calls to variables, combine them to an array and await them all at once."
Instead
asyncfunctionprocessData() {
const promise1 = downloadFromService1();
const promise2 = downloadFromService2();
const promise3 = downloadFromService3();
const allResults = awaitPromise.all([promise1, promise2, promise3]);
Post a Comment for "Best Es6 Way To Get Name Based Results With Promise.all"