javascript - Chaining 2 asynchronous calls (promise API) to run serially - Stack Overflow

This is similar to a question I posted today, but needs the request chained serially. I have two asynch

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 the query.

var Db.get = function(key){
    var deferred = $q.defer();

     //send async req
    var req = ....
    req.success = function(d){
        deferred.resolve(d)
    };
    req.failure = function(d){
        deferred.reject(d)
    }

    return deferred.promise;
}

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

    console.log("At 3")
};

I should be thinking it wrongly, as I expect console.log("At 3") never to be printed in success scenario as I return after console.log("At 2"). But when I run, in the console I see these order

console.log("At 1")
console.log("At 3")
console.log("At 2")

I was thinking then would block till it get response from the promise (returned by get() ). so, everything in someFn execute serially. Is this assumption wrong? What is the best way to chain two asynchronous operation, which uses promises, to run serially.

Thanks.

EDIT:

I tried what Ketan suggested Chaining Ajax calls in AngularJs .

var someFn = function(id){
            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
                    return null;
                }).then(function (d) {
                    return d;
        });

        console.log("At 3")
    };

Still, if I make a call like

var res = someFn(1)
console.log(res) /// undefined

chrome terminal shows At 2 after undefined. I am not sure why the result retuned by someFn not assigned to res.

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 the query.

var Db.get = function(key){
    var deferred = $q.defer();

     //send async req
    var req = ....
    req.success = function(d){
        deferred.resolve(d)
    };
    req.failure = function(d){
        deferred.reject(d)
    }

    return deferred.promise;
}

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

    console.log("At 3")
};

I should be thinking it wrongly, as I expect console.log("At 3") never to be printed in success scenario as I return after console.log("At 2"). But when I run, in the console I see these order

console.log("At 1")
console.log("At 3")
console.log("At 2")

I was thinking then would block till it get response from the promise (returned by get() ). so, everything in someFn execute serially. Is this assumption wrong? What is the best way to chain two asynchronous operation, which uses promises, to run serially.

Thanks.

EDIT:

I tried what Ketan suggested Chaining Ajax calls in AngularJs .

var someFn = function(id){
            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
                    return null;
                }).then(function (d) {
                    return d;
        });

        console.log("At 3")
    };

Still, if I make a call like

var res = someFn(1)
console.log(res) /// undefined

chrome terminal shows At 2 after undefined. I am not sure why the result retuned by someFn not assigned to res.

Share Improve this question edited May 23, 2017 at 12:06 CommunityBot 11 silver badge asked May 1, 2013 at 2:15 bsrbsr 58.8k88 gold badges218 silver badges321 bronze badges 3
  • 2 See this question that Pawel answered yesterday. stackoverflow./questions/16284403/… – Ketan Commented May 1, 2013 at 2:20
  • thanks Ketan. Will try it out. – bsr Commented May 1, 2013 at 2:23
  • Because someFn didn't return anything. You need to use someFn().then() and access the value from within the function passed to then. Check out this video where I discuss promises: plus.google./events/cljavmi7kpup1fso43k3fkpk2eg – Josh David Miller Commented May 1, 2013 at 7:14
Add a ment  | 

2 Answers 2

Reset to default 4

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.

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")
});

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744229995a4564199.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信