1

How do i chain promises sequentially within for loop, i have seen lot of examples on google to do this but i couldn't implement for my case: i have gone through this link for sequential chaining of Promises.

What I'm trying to acheive:
Promise1: login();
Promise2: sync();

sync function calls another service complete() for an array of elements. These array of elements must be done sequentially.

ServiceA.login().  
      then(function(response){
                   ServiceA.sync()
                        .then(function(response){

                         })
      })

function sync(){
     ServiceB.complete()
                    .then(function(){
                               var promises = [];
                               angular.forEach(response, function (value) {
                    // The below service call doSomething() must be done sequentially for each "value"
                                  promises.push(doSomething(value));
                               });
                               $q.all(promises).then(function () {


                                        });
                                    });

                      })
}

How do I capture the error occuring in each Promise?

Update:
I have tried the approach suggested by @zaptree with the following code:

ServiceA.login()
.then(function(response){
    // you must always return your promise
    return ServiceA.sync()

})
// don't nest the .then make them flat like this
.then(function(response){

})
.catch(function(){
    // if you made sure to always return your promises this catch will catch any errors throws in your promise chain including errors thrown by doSomething()
});

function sync(){
// you must always return your promise
return ServiceB.complete()
    .then(function(){

        var result = $q.when();
        angular.forEach(response, function (value) {
            result = result.then(doSomething(value)); // problem is here that doSomething function is being called before the first call it is resolved
// doSomething is a http call.
        });
        return result;
    })
    .then(function(){
        // the array of promises has run sequentially and is completed
    });

}

 function doSomething(data){
      return $http({
            method: 'POST',
            url: '/api/do',
            data: data,
            headers: {
                "Content-Type": "application/json"
            }
        }).then(function (response) {

        }, function (error) {

        });
  }

If the response in the near the for each loop has 2 values (valuea, valueb) in it, the code is behaving as follows:
1. calling doSomething(valuea)
2. calling doSomething(valueb) before the above promise is resolved.
Expected behaviour:
after the POST method has succesfully completed by the call doSOmething(valuea), then the another POST call should happend i.e., soSomething(valueb).

3
  • Why sequentially? are they depending on each other? Commented Dec 21, 2016 at 22:33
  • Yes these are dependent on each other Commented Dec 21, 2016 at 22:36
  • 1
    $q.all([...]) fails if either one fails however they run in parallel. In order to run sequentially you must chain them via .then(). Commented Dec 21, 2016 at 22:40

2 Answers 2

2

Here's what I came up with. You'll need to reduce the array into a single promise.

var results = [...];
var sequentialPromise = results.reduce(function(a, b) {
  return a.then(function(){
   return doSomething(b);
  });
}, $q.resolve());

sequentialPromise.then(function(){...});
Sign up to request clarification or add additional context in comments.

3 Comments

won't that doSomething() on the chain of promises, as your are building it?
The first one does. the others one only happens when the callback gets called IE - the previous promise has finished.
Maybe I'm missing something, but during the first loop in reduce, isn't a a resolved promise? Doesn't reduce need to return a.then(function(){ return doSomething(b) }); ?
0

So here is an example on how you would do the sequential promises with Q, also some improvements on how to do your promises so you can properly catch errors thrown at any point in your promise chain. You must always make sure to return a promise on any method that uses them. Also avoid pyramid code by not nesting the .then to make your code cleaner:

ServiceA.login()
    .then(function(response){
        // you must always return your promise
        return ServiceA.sync()

    })
    // don't nest the .then make them flat like this
    .then(function(response){

    })
    .catch(function(){
        // if you made sure to always return your promises this catch will catch any errors throws in your promise chain including errors thrown by doSomething()
    });

function sync(){
    // you must always return your promise
    return ServiceB.complete()
        .then(function(){

            var result = $q.when();
            angular.forEach(response, function (value) {
                result = result.then(doSomething(value));
            });
            return result;
        })
        .then(function(){
            // the array of promises has run sequentially and is completed
        });

}

5 Comments

Does this work for the services? or does it work for both factory and services?
This will work however you need to specify a callback function in the .then()
I'm getting error near var result=$q(); I have injected in my function like ServiceB.inject=['$q'].
Error in the console: TypeError: [$q:norslvr] Expected resolverFn, got 'undefined'
hmm looks like $q requires a resolver which is pretty silly: docs.angularjs.org/error/$q/norslvr you can do $q.when() instead I believe.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.