Skip to content

promises

Most here is from promises_google , good page.

Hands on, first make sure you got node setup correctly since promises are not a native construct.

A Promise is a proxy for a value not necessarily known when the promise is created.

installation

For older versions of node/js we may need the Q library, but for at least nov 6 seems to work without:

node -v
v6.12.3
# if not : npm install --save Q}

Promises differ from callbacks in that they are an object that is returned. An object holding the callbacks.

promise
var myPromise = new Promise(function(resolve,reject) {
  return reject("I just always reject this");
});

console.dir(myPromise);

myPromise.then(function(result) {
    console.log("OK : " + result);
}, function (err) {
    console.log(err);
})

# this version would print :
# Promise { <rejected> 'I just always reject this' }
# I just always reject this

This creates a promise object with a callback function with two functions: one for resolving and one for rejecting the promise.

The callback function given to the promise is typically a lengthy one, since otherwise you could just call it synchronous. Though not in this example, where for clarity I just always reject directly. You could rewrite the function like this for a more asynchronous feel( and not failing this time)

promise
1
2
3
4
5
6
myPromise = new Promise((resolve, reject) => {
    setTimeout(() => {
        message = "Yep, good";
        resolve(message);
    }, 2000)
})

Now it would print two lines, with about 2 seconds in between the first and the second two.

output
1
2
3
Promise { <pending> }
Promise { 'Yep, good' }
OK : Yep, good

So it will just wait for the data to become available. One of the major advantages is that no matter when you called the .then() function the outcome will be the same. If we build in a timer for the call itself :

call after some time
var myPromise = new Promise(function(resolve,reject) {
    setTimeout(() => {
        message = "Yep, good";
        resolve(message);
    }, 2000)
});

console.dir(myPromise);

setTimeout(() => {
    myPromise.then(function(result) {
        console.dir(myPromise);
        console.log("OK : " + result);
    }, function (err) {
        console.log(err);
    })
    }, 4000)

It will print the same line, but now with 4 seconds between.

output
1
2
3
Promise { <pending> }
Promise { 'Yep, good' }
OK : Yep, good

The event had already happened when we ran .then() but it handles that ok.

all()

Another neat function that let's you call multiple promises in a certain order.

promise.all()
var message = "";

promise1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        message += "my";
        resolve(message);
    }, 1000)
})

promise2 = new Promise((resolve, reject) => {
    setTimeout(() => {
        message += " first";
        resolve(message);
    }, 2000)
})

promise3 = new Promise((resolve, reject) => {
    setTimeout(() => {
        message += " promise";
        resolve(message);
    }, 3000)
})

var printResult = (results) => {console.log("Results = ", results, "message = ", message)}

function main() {
    // See the order of promises. Final result will be according to it
    Promise.all([promise1, promise2, promise3]).then(printResult);
    Promise.all([promise2, promise1, promise3]).then(printResult);
    Promise.all([promise3, promise2, promise1]).then(printResult);
    console.log("""" + message);

    promise1.then(printResult);
    promise1.then(printResult);
    promise1.then(printResult);
}

As you can see calling multiple times is not a problem, the promise result stays present, the output is what you would expect from the code :

output
1
2
3
4
5
6
7
8
""
Results =  my message =  my
Results =  my message =  my
Results =  my message =  my

Results =  [ 'my', 'my first', 'my first promise' ] message =  my first promise
Results =  [ 'my first', 'my', 'my first promise' ] message =  my first promise
Results =  [ 'my first promise', 'my first', 'my' ] message =  my first promise
  • Since promise1 is available after 1 second, the first message is printed directly : the still empty message.
  • promise1 is known after 1 second so 3 times "my".
  • Then 2 seconds later all() results are known and the complete results are printed.

chaining

Simplest example probably :

chaining
var promise = new Promise(function(resolve, reject) {
    resolve(1);
});

promise.then(function(val) {
    console.log(val); // 1
    return val + 2;
}).then(function(val) {
    console.log(val); // 3
})

This prints 1 and 3 : The values get transformed when you return the altered value, so this just cascades into the new .then() etc.

If you return a value from then(), the next .then() is called with that value. However if you return something promise-like, the next then() waits on it, and is only called when that promise settles (succeeds/fails).

So it is also possible to make asynchronous 'cascade' by returning promises from .then() This makes a promise wait for a promise :

async
asyncThing1().then(function() {
    return asyncThing2();
}).then(function() {
    return asyncThing3();
}).catch(function(err) {
    return asyncRecovery1();
}).then(function() {
    return asyncThing4();
}, function(err) {
    return asyncRecovery2();
}).catch(function(err) {
    console.log("Don't worry about it");
}).then(function() {
    console.log("All done!");
})

..unfinished !