How to Return Many Promises and Wait For Them All Before Doing Other Stuff

How to return many Promises and wait for them all before doing other stuff

You can use Promise.all (spec, MDN) for that: It accepts a bunch of individual promises and gives you back a single promise that is resolved when all of the ones you gave it are resolved, or rejected when any of them is rejected.

So if you make doSomeAsyncStuff return a promise, then:

    const promises = [];
// ^^^^^−−−−−−−−−−−−−−−−−−−−−−−−−−− use `const` or `let`, not `var`

for (let i = 0; i < 5; i++) {
// ^^^−−−−−−−−−−−−−−−−−−−−−−−− added missing declaration
promises.push(doSomeAsyncStuff());
}

Promise.all(promises)
.then(() => {
for (let i = 0; i < 5; i++) {
// ^^^−−−−−−−−−−−−−−−− added missing declaration
doSomeStuffOnlyWhenTheAsyncStuffIsFinish();
}
})
.catch((e) => {
// handle errors here
});

MDN has an article on promises here. I also cover promsies in detail in Chapter 8 of my book JavaScript: The New Toys, links in my profile if you're interested.

Here's an example:

 function doSomethingAsync(value) {
return new Promise((resolve) => {
setTimeout(() => {
console.log("Resolving " + value);
resolve(value);
}, Math.floor(Math.random() * 1000));
});
}

function test() {
const promises = [];

for (let i = 0; i < 5; ++i) {
promises.push(doSomethingAsync(i));
}

Promise.all(promises)
.then((results) => {
console.log("All done", results);
})
.catch((e) => {
// Handle errors here
});
}

test();

Wait until all promises complete even if some rejected

Benjamin's answer offers a great abstraction for solving this issue, but I was hoping for a less abstracted solution. The explicit way to to resolve this issue is to simply call .catch on the internal promises, and return the error from their callback.

let a = new Promise((res, rej) => res('Resolved!')),
b = new Promise((res, rej) => rej('Rejected!')),
c = a.catch(e => { console.log('"a" failed.'); return e; }),
d = b.catch(e => { console.log('"b" failed.'); return e; });

Promise.all([c, d])
.then(result => console.log('Then', result)) // Then ["Resolved!", "Rejected!"]
.catch(err => console.log('Catch', err));

Promise.all([a.catch(e => e), b.catch(e => e)])
.then(result => console.log('Then', result)) // Then ["Resolved!", "Rejected!"]
.catch(err => console.log('Catch', err));

Taking this one step further, you could write a generic catch handler that looks like this:

const catchHandler = error => ({ payload: error, resolved: false });

then you can do

> Promise.all([a, b].map(promise => promise.catch(catchHandler))
.then(results => console.log(results))
.catch(() => console.log('Promise.all failed'))
< [ 'Resolved!', { payload: Promise, resolved: false } ]

The problem with this is that the caught values will have a different interface than the non-caught values, so to clean this up you might do something like:

const successHandler = result => ({ payload: result, resolved: true });

So now you can do this:

> Promise.all([a, b].map(result => result.then(successHandler).catch(catchHandler))
.then(results => console.log(results.filter(result => result.resolved))
.catch(() => console.log('Promise.all failed'))
< [ 'Resolved!' ]

Then to keep it DRY, you get to Benjamin's answer:

const reflect = promise => promise
.then(successHandler)
.catch(catchHander)

where it now looks like

> Promise.all([a, b].map(result => result.then(successHandler).catch(catchHandler))
.then(results => console.log(results.filter(result => result.resolved))
.catch(() => console.log('Promise.all failed'))
< [ 'Resolved!' ]

The benefits of the second solution are that its abstracted and DRY. The downside is you have more code, and you have to remember to reflect all your promises to make things consistent.

I would characterize my solution as explicit and KISS, but indeed less robust. The interface doesn't guarantee that you know exactly whether the promise succeeded or failed.

For example you might have this:

const a = Promise.resolve(new Error('Not beaking, just bad'));
const b = Promise.reject(new Error('This actually didnt work'));

This won't get caught by a.catch, so

> Promise.all([a, b].map(promise => promise.catch(e => e))
.then(results => console.log(results))
< [ Error, Error ]

There's no way to tell which one was fatal and which was wasn't. If that's important then you're going to want to enforce and interface that tracks whether it was successful or not (which reflect does).

If you just want to handle errors gracefully, then you can just treat errors as undefined values:

> Promise.all([a.catch(() => undefined), b.catch(() => undefined)])
.then((results) => console.log('Known values: ', results.filter(x => typeof x !== 'undefined')))
< [ 'Resolved!' ]

In my case, I don't need to know the error or how it failed--I just care whether I have the value or not. I'll let the function that generates the promise worry about logging the specific error.

const apiMethod = () => fetch()
.catch(error => {
console.log(error.message);
throw error;
});

That way, the rest of the application can ignore its error if it wants, and treat it as an undefined value if it wants.

I want my high level functions to fail safely and not worry about the details on why its dependencies failed, and I also prefer KISS to DRY when I have to make that tradeoff--which is ultimately why I opted to not use reflect.

How to wait for all Promises to be finished

First, you have to fix both functionOne() and functionTwo() so that they resolve() the promise they create when their timer fires. Without that, they just create a promise that never resolves which isn't very useful and does not notify the caller when they are done.

Then, to run them in parallel, use Promise.all() which will let you call both functions and then it will track both returned promises together and the promise returned from the call to Promise.all() will resolve when both functions have completed or reject if either one of the functions rejected their promise.

If your example here, none of your promises rejects, but if you want to know when all promises have finished even if some reject, then you would use Promise.allSettled() instead of Promise.all(). The main difference is that Promise.all() will short-circuit and reject it's promise as soon as any promise you pass it rejects, whereas Promise.allSettled() will wait until all promises are done, regardless of resolve/reject. Though you aren't using it here, the resolved value from Promise.allSettled() is different also so that you can tell which promises rejected and which resolved.

Here's a runnable (in the snippet) example that uses Promise.all().
You can swap in Promise.allSettled() if that's the behavior you'd rather see:

    const logger = console;

const functionOne = function () {
logger.info("Starting functionOne");
return new Promise(resolve => {
setTimeout(function () {
logger.info("Finished functionOne after 20 sec.");
resolve();
}, 20000);
});
};

const functionTwo = function () {
logger.info("Starting functionTwo");
return new Promise(resolve => {
setTimeout(function () {
logger.info("Finished functionTwo after 10 sec.");
resolve();
}, 10000);
});
};
const runningFunctions = function () {
logger.info('Start jobs');
return Promise.all([functionOne(), functionTwo()]);
}

runningFunctions().then(() => {
logger.info(`All done after 20 sec.`);
}).catch(err => {
console.log(err);
});

I need to return a value from a asynchronous code, but I just get the Promise object in { pending } status

What you want is to use Promise.all(allSpecFilesArr) because that is an array of promises. You can await it and you will receive an array of data returned from the inner resolved promises.

const fileContents = await Promise.all(allSpecFilesArr);

How do I wait for a promise to finish before returning the variable of a function?

Instead of returning a resultsArray you return a promise for a results array and then then that on the call site - this has the added benefit of the caller knowing the function is performing asynchronous I/O. Coding concurrency in JavaScript is based on that - you might want to read this question to get a broader idea:

function resultsByName(name)
{
var Card = Parse.Object.extend("Card");
var query = new Parse.Query(Card);
query.equalTo("name", name.toString());

var resultsArray = [];

return query.find({});

}

// later
resultsByName("Some Name").then(function(results){
// access results here by chaining to the returned promise
});

You can see more examples of using parse promises with queries in Parse's own blog post about it.

Wait for all promises to resolve before updating state and redirect

Use Promise.all() to wait for all promises to resolve before doing something else:

const handleSubmit = () => {
Promise.all(files.map(file =>
storageRef
.ref(`${data.firebaseRef}/${file.id}`)
.put(file)
)).then(() => {
// Only if all files are uploaded to firebase then I need to do something
})
}

How to make promise wait till all requests in a loop are completed?

Asynchronous execution in parallel (order of execution is unimportant, better performance):

Use Promise.all.

Asynchronous execution in series (order of execution is important, only start each request after the previous one resolves):

Use for await...of.

How to wait for a JavaScript Promise to resolve before resuming function?

I'm wondering if there is any way to get a value from a Promise or
wait (block/sleep) until it has resolved, similar to .NET's
IAsyncResult.WaitHandle.WaitOne(). I know JavaScript is
single-threaded, but I'm hoping that doesn't mean that a function
can't yield.

The current generation of Javascript in browsers does not have a wait() or sleep() that allows other things to run. So, you simply can't do what you're asking. Instead, it has async operations that will do their thing and then call you when they're done (as you've been using promises for).

Part of this is because of Javascript's single threadedness. If the single thread is spinning, then no other Javascript can execute until that spinning thread is done. ES6 introduces yield and generators which will allow some cooperative tricks like that, but we're quite a ways from being able to use those in a wide swatch of installed browsers (they can be used in some server-side development where you control the JS engine that is being used).


Careful management of promise-based code can control the order of execution for many async operations.

I'm not sure I understand exactly what order you're trying to achieve in your code, but you could do something like this using your existing kickOff() function, and then attaching a .then() handler to it after calling it:

function kickOff() {
return new Promise(function(resolve, reject) {
$("#output").append("start");

setTimeout(function() {
resolve();
}, 1000);
}).then(function() {
$("#output").append(" middle");
return " end";
});
}

kickOff().then(function(result) {
// use the result here
$("#output").append(result);
});

This will return output in a guaranteed order - like this:

start
middle
end

Update in 2018 (three years after this answer was written):

If you either transpile your code or run your code in an environment that supports ES7 features such as async and await, you can now use await to make your code "appear" to wait for the result of a promise. It is still programming with promises. It does still not block all of Javascript, but it does allow you to write sequential operations in a friendlier syntax.

Instead of the ES6 way of doing things:

someFunc().then(someFunc2).then(result => {
// process result here
}).catch(err => {
// process error here
});

You can do this:

// returns a promise
async function wrapperFunc() {
try {
let r1 = await someFunc();
let r2 = await someFunc2(r1);
// now process r2
return someValue; // this will be the resolved value of the returned promise
} catch(e) {
console.log(e);
throw e; // let caller know the promise was rejected with this reason
}
}

wrapperFunc().then(result => {
// got final result
}).catch(err => {
// got error
});

async functions return a promise as soon as the first await is hit inside their function body so to the caller an async function is still non-blocking and the caller must still deal with a returned promise and get the result from that promise. But, inside the async function, you can write more sequential-like code using await on promises. Keep in mind that await only does something useful if you await a promise so in order to use async/await, your asynchronous operations must all be promise-based.



Related Topics



Leave a reply



Submit