JavaScript promises, mastering the asynchronous

Magus
6,257 views

Open Source Your Knowledge, Become a Contributor

Technology knowledge has to be shared and made accessible for free. Join the movement.

Create Content

Sometimes you have multiple asynchronous tasks to perform and you have to start something when every task is done. When using promises, you can do that with Promise.all. Run the following code to understand the basics of it.

Promise.all example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function job(delay) {
return new Promise(function(resolve) {
setTimeout(function() {
console.log('Resolving', delay);
resolve('done ' + delay);
}, delay);
});
}
var promise = Promise.all([job(1000), job(2000), job(500), job(1500)]);
promise.then(function(data) {
console.log('All done');
data.forEach(function(text) {
console.log(text);
});
});
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

As you can see, Promise.all returns a promise. The received data is an array containing the data of each given promise. The promise is resvoled when all given promises are resolved.

Beware, Promise.all has a fail-fast behaviour. If a given promise is rejected, the resulting promise of Promise.all will be rejected at this exact moment. It will not wait for the other promises to complete, and the only received data is the error of the rejected request. See the following example for a better understanding.

Promise.all fail-fast behaviour
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
let p1 = new Promise(function(resolve, reject) {
setTimeout(resolve, 500, 'p1');
});
let p2 = new Promise(function(resolve, reject) {
setTimeout(resolve, 1000, 'p2');
});
let p3 = new Promise(function(resolve, reject) {
setTimeout(resolve, 1200, 'p3');
});
let p4 = new Promise(function(resolve, reject) {
setTimeout(reject, 300, 'p4');
});
let p5 = new Promise(function(resolve, reject) {
setTimeout(resolve, 800, 'p5');
});
let promise = Promise.all([p1, p2, p3, p4, p5]);
promise
.then(function(data) {
data.forEach(function(data) {
cconsole.log(data);
});
})
.catch(function(error) {
console.error('error', error);
});
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

As you can see, error p4 is displayed. We can't access the result of the other promises. You should only use Promise.all when you need for all of your promises to resolve successfully.

What if you want to start multiple asynchronous jobs at once and you want results even if a job is rejected? Just use catch. See the following example.

Promise.all with catch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
let p1 = new Promise(function(resolve, reject) {
setTimeout(resolve, 500, 'p1');
});
let p2 = new Promise(function(resolve, reject) {
setTimeout(resolve, 1000, 'p2');
});
let p3 = new Promise(function(resolve, reject) {
setTimeout(resolve, 1200, 'p3');
});
let p4 = new Promise(function(resolve, reject) {
setTimeout(reject, 300, 'p4');
});
let p5 = new Promise(function(resolve, reject) {
setTimeout(resolve, 800, 'p5');
});
let promise = Promise.all([p1.catch(function() {}), p2.catch(function() {}), p3.catch(function() {}), p4.catch(function() {}), p5.catch(function() {})]);
promise
.then(function(data) {
data.forEach(function(data) {
console.log(data);
});
})
.catch(function(error) {
console.error('error', error);
});
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

In this example, we don't give the promises directly to Promise.all. We give the result of p.catch (this is an auto-resolved promise) so Promise.all won't stop. In this case, however, you have to test the received data yourself to check for errors.

Open Source Your Knowledge: become a Contributor and help others learn. Create New Content