Skip to content Skip to sidebar Skip to footer

Chaining 2 Asynchronous Calls (promise API) To Run Serially

This is similar to a question I posted today, but needs the request chained serially. I have two asynchronous requests, where the second request needs the result of first to send t

Solution 1:

The place where your having difficulty is that .then doesn't actually block. It helps you convert synchronous code into asynchronous code, but it doesn't do so for you. Lets start by considering the synchronous code you are trying to re-write. Imagine Db.get was a synchronous function that returned a value, rather than a promise:

var someFn = function (id){
    try {
        var d = Db.get(id, "abc");
        console.log("At 1");
        var d = Db.get(d.id, "def");
        console.log("At 2")
        return d;
    } catch (ex) {
        console.log("At 3")
    }
};

In this case, when I call someFn I get a value, not a promise. That is to say the entire function is synchronous.

If we temporarily fast forward a few years and imagine we could use ES6. That would let us re-write your function as:

var someFn = $q.async(function* (id){
    try {
        var d = yield Db.get(id, "abc");
        console.log("At 1");
        var d = yield Db.get(d.id, "def");
        console.log("At 2")
        return d;
    } catch (ex) {
        console.log("At 3")
    }
});

That looks very similar, but this time we have Db.get returning a promise, and someFn() will also always return a promise. The yield keyword actually "pauses" the current function until the promise is fulfilled. This lets it look just like the synchronous code, but it's actually asynchronous.

Rewind to the present, and we need to work out how to write this. The second argument of a .then call is an error handler, so the exact equivalent to the ES6 example would be:

var someFn = function (id){
    return Db.get(id, "abc")
        .then(function (d) {
            console.log("At 1");
            return Db.get(d.id, "def");
        })
        .then(function (d) {
            console.log("At 2");
            return d;
        })
        .then(null, function (ex) {
            console.log("At 3")
        });
});

Note how each return is only returning from its current function scope. There's no way to force it to jump all the way out of someFn.

Another interesting experiment to do is:

Db.get('id', 'abc')
  .then(function () {
    console.log('B');
  });
console.log('A');

The above will always log:

A
B

because .then doesn't block.


Solution 2:

I was thinking then would block till it get response from the promise

No. Promises in JS are no transparent, blocking futures, but just a pattern to chain callbacks. The promise is returned before the callback is executed - and At 3 is logged after .then returns, but before the callback executed. And if you return in the callback, it doesn't really matter to the outer someFn.

You rather would use something like

var someFn = function(id){
    return Db.get(id, "abc")
      .then(function (d) {
        console.log("At 1")
        return Db.get(d.id, "def");
      })
      .then(function (d) {
        console.log("At 2")
        return d
      }, function (e) {
        //error
      });
}
someFn().then(function(d) {
    console.log("At 3")
});

Post a Comment for "Chaining 2 Asynchronous Calls (promise API) To Run Serially"