Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS: $q wait for all even when 1 rejected

Tags:

angularjs

I've been trying to wait for a couple of promises with Angular's $q but there seems to be no option to 'wait for all even when a promis is rejected'. I've created an example (http://jsfiddle.net/Zenuka/pHEf9/21/) and I want a function to be executed when all promises are resolved/rejected, is that possible? Something like:

$q.whenAllComplete(promises, function() {....}) 

EDIT: In the example you see that the second service fails and immediately after that the function in $q.all().then(..., function(){...}) is being executed. I want to wait for the fifth promise to be completed.

like image 528
Zenuka Avatar asked Sep 19 '13 06:09

Zenuka


People also ask

What does $q do in AngularJS choose all that apply?

$q is an angular defined service. It's the same as new Promise(). But $q takes things to the next level by enhancing additional feature that developers can use to perform complex tasks more simply. resolve(value) – resolves the derived promise with the value.

What is Q defer () in AngularJS?

$q. defer() allows you to create a promise object which you might want to return to the function that called your login function.

What is $timeout in AngularJS?

This '$timeout' service of AngularJS is functionally similar to the 'window. setTimeout' object of vanilla JavaScript. This service allows the developer to set some time delay before the execution of the function.

What is $HTTP in AngularJS?

$http is an AngularJS service for reading data from remote servers.


2 Answers

Ok, I've implemeted a basic version myself (I only want to wait for an array of promises). Anyone can extend this or create a cleaner version if they want to :-) Check the jsfiddle to see it in action: http://jsfiddle.net/Zenuka/pHEf9/

angular.module('test').config(['$provide', function ($provide) {     $provide.decorator('$q', ['$delegate', function ($delegate) {         var $q = $delegate;          // Extention for q         $q.allSettled = $q.allSettled || function (promises) {             var deferred = $q.defer();             if (angular.isArray(promises)) {                 var states = [];                 var results = [];                 var didAPromiseFail = false;                 if (promises.length === 0) {                      deferred.resolve(results);                     return deferred.promise;                 }                  // First create an array for all promises with their state                 angular.forEach(promises, function (promise, key) {                     states[key] = false;                 });                  // Helper to check if all states are finished                 var checkStates = function (states, results, deferred, failed) {                     var allFinished = true;                     angular.forEach(states, function (state, key) {                         if (!state) {                             allFinished = false;                         }                     });                     if (allFinished) {                         if (failed) {                             deferred.reject(results);                         } else {                             deferred.resolve(results);                         }                     }                 }                  // Loop through the promises                 // a second loop to be sure that checkStates is called when all states are set to false first                 angular.forEach(promises, function (promise, key) {                     $q.when(promise).then(function (result) {                         states[key] = true;                         results[key] = result;                         checkStates(states, results, deferred, didAPromiseFail);                     }, function (reason) {                         states[key] = true;                         results[key] = reason;                         didAPromiseFail = true;                         checkStates(states, results, deferred, didAPromiseFail);                     });                 });             } else {                 throw 'allSettled can only handle an array of promises (for now)';             }              return deferred.promise;         };          return $q;     }]); }]); 
like image 94
Zenuka Avatar answered Sep 18 '22 18:09

Zenuka


Analogous to how all() returns an array/hash of the resolved values, the allSettled() function from Kris Kowal's Q returns a collection of objects that look either like:

{ state: 'fulfilled', value: <resolved value> } 

or:

{ state: 'rejected', reason: <rejection error> } 

As this behavior is rather handy, I've ported the function to Angular.js's $q:

angular.module('your-module').config(['$provide', function ($provide) {     $provide.decorator('$q', ['$delegate', function ($delegate) {         var $q = $delegate;          $q.allSettled = $q.allSettled || function allSettled(promises) {             // Implementation of allSettled function from Kris Kowal's Q:             // https://github.com/kriskowal/q/wiki/API-Reference#promiseallsettled              var wrapped = angular.isArray(promises) ? [] : {};              angular.forEach(promises, function(promise, key) {                 if (!wrapped.hasOwnProperty(key)) {                     wrapped[key] = wrap(promise);                 }             });              return $q.all(wrapped);              function wrap(promise) {                 return $q.when(promise)                     .then(function (value) {                         return { state: 'fulfilled', value: value };                     }, function (reason) {                         return { state: 'rejected', reason: reason };                     });             }         };          return $q;     }]); }]); 

Credit goes to:

  • Zenuka for the decorator code
  • Benjamin Gruenbaum for pointing me in the right direction
  • The all implementation from Angular.js source
like image 43
Michael Kropat Avatar answered Sep 19 '22 18:09

Michael Kropat