Search code examples
javascriptangularjsangular-promiseangular-resource

How to use angularjs $q.all() with an asynchronously created array of promises


I'm trying to use $q.all() to wait until a bunch of promises is resolved. For this purpose, i created a promises array and I pass it to the all() method, but this doesn't seem to work. The promises array is filled with the promises returned by the $resource objects, that are created in each iteration, and I think that's the problem because the promises array is filled asynchronously.

I have come to this conclusion because the promise, array of promises, returned by the $q.all() method is always an empty array. It's like the $q.all() method doesn't wait for the array to get filled up. But I'm not sure if that is the problem.

I will really appreciate any help in this matter and, if it is not possible to achieve what I want with $ q.all(), i would like to see other ways to execute code after all the promises are resolved.

Here is the code I am currently using

        var promisesArray = [];            
        var images, postObject;
        files.readFile('images.txt')
        .then(function (data) {
            images= angular.fromJson(data);                
            images.forEach(function (image, idx) {
                var deferred = $q.defer();                    
                if (!image.sent) {
                    files.readFile(image.name)
                    .then(function (data) {
                        postObject = angular.fromJson(data);
                        $resource(EndPointsService.baseURL + "images").save(postObject, function(data) {
                            deferred.resolve(data);
                            if (data.status) {                                    
                                image.sent= true;                                    
                            }
                        },function(error){
                          console.log(error);  
                        });
                        promisesArray.push(deferred.promise);
                    },function(error){
                        console.log(error);
                    });
                }
            });


              $q.all(promisesArray).then(function (data) {
                    console.log(data);
                    files.writeFile("images.txt", images)
                    .then(function (data) {                        
                        console.log(data);
                    }, function (error) {
                        console.log(error);
                    });
              });
       },function(error){
          console.log(error)
       });

Solution

  • The .then method of a promise returns a new promise from data returned to it.

    Create the promise array inside the .then method and return the $q.all promise to that .then method:

    ̶v̶a̶r̶ ̶p̶r̶o̶m̶i̶s̶e̶s̶A̶r̶r̶a̶y̶ ̶=̶ ̶[̶]̶;̶            
    var images, postObject;
    var arrayPromise = files.readFile('images.txt')
      .then(function (data) {
        ͟v͟a͟r͟ ͟p͟r͟o͟m͟i͟s͟e͟s͟A͟r͟r͟a͟y͟ ͟=͟ ͟[͟]͟;͟
        images= angular.fromJson(data);                
        images.forEach(function (image, idx) {
            ̶v̶a̶r̶ ̶d̶e̶f̶e̶r̶r̶e̶d̶ ̶=̶ ̶$̶q̶.̶d̶e̶f̶e̶r̶(̶)̶;̶                    
            if (!image.sent) {
                var promise = files.readFile(image.name)
                  .then(function (data) {
                    postObject = angular.fromJson(data);
                    var url = EndPointsService.baseURL + "images"
                    ͟r͟e͟t͟u͟r͟n͟ $resource(url).save(postObject).$promise;
                });
                promisesArray.push(promise);
            };
        });
        ͟r͟e͟t͟u͟r͟n͟ $q.all(promisesArray);
    });
    
    
    arrayPromise.then(function (dataArray) {
        console.log(dataArray);
        //Process data here
    });