Conteng Evolved

Stuff, mostly software development stuff

Understanding JavaScript Promise With Examples - No More Callback Hell?

These are some simple examples for JavaScript’s Promise object. Use it to make your asynchronous operations code more managable and avoid callback hells.

Basic Example

In this example, we want to run something after an async task. Using the Promise syntax, the code seems to flow the async operation into a more synchronous style. At least that is how I see and value it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
new Promise(function(resolve) {

    // run some async task that will take 1 second
    setTimeout(function() {
        console.log('Async task runs');
        resolve();
    }, 1000);

}).then(function() {

    // this code runs
    console.log('Then run this code');

});

Chaining – Multiple Async Tasks in Sequence

Sometimes it is useful to run multiple async task in sequence. Let’s say we need to:

  1. Perform an AJAX call to get userId from the server.
  2. With the userId, perform another AJAX call to retrieve products for the user.
  3. Render the products on screen.
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
new Promise(function(resolve) {

    // 1. first async task
    setTimeout(function() {
        var userId = 'user-123'; // assume this is an AJAX call's response
        console.log('Retrieved userId');
        resolve(userId);
    }, 1000);

}).then(function(value) {

    // 2. second async task
    // value is the resolved userID from the previous promise
    return new Promise(function(resolve) {
        setTimeout(function() {
            var products = 'product-abc';
            console.log('Retrieved products');
            resolve(products);
        }, 1000);
    });

}).then(function(value) {

    // 3. now we can render the products after two async tasks are done
    console.log('Rending product ' + value);

});

Fork/Join

Another common pattern is to have multiple tasks start as soon as they can. As soon as all the tasks complete, we execute some code. The difference between this and chaining above is all the promises run at the same time instead of running one by one in sequence.

A scenario for this could look like:

  1. Get current weather from server.
  2. Get user profile from server.
  3. Get latest news from a server.
  4. Render data from the three tasks.
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
var promiseToGetWeather = new Promise(function(resolve) {
    setTimeout(function() {
        console.log('weather ok');
        var weather = 'cloudy';
        resolve(weather);
    }, 1500);
});

var promiseToGetProfile = new Promise(function(resolve) {
    setTimeout(function() {
        console.log('profile ok');
        var profile = 'bob';
        resolve(profile);
    }, 500);
});

var promiseToGetNews = new Promise(function(resolve) {
    setTimeout(function() {
        console.log('news ok');
        var news = 'meteor rising';
        resolve(news);
    }, 1000);
});

Promise.all([
    promiseToGetWeather, promiseToGetProfile, promiseToGetNews
]).then(function(value) {
    // value contains an array ['cloudy', 'bob', 'meteor rising'] as resolved by the promises
    console.log('Rendering data');
    console.log(value);
});

Details

Hopefully these examples make it easier to get started with JavaScript promises. It is still useful to refer to Promise documentation on other features like error handling and Promise.race().

Note that all the examples can executed on your browser’s developer console – provided the browser supports Promise (Chrome >= 32; Firefox >= 29; IE >= 11; Opera >= 19; Safari >= 7.1).

Comments