Javascript: How to iterate on array using promises? Javascript: How to iterate on array using promises? angularjs angularjs

Javascript: How to iterate on array using promises?


I wonder if there is a better way?

Yes. Avoid the deferred antipattern!

function isGood(number) {  return $timeout(function() {    if (<some condition on number>) {      return number; // Resolve with the number, simplifies code below    } else {      throw new Error("…");    }  }, 100);}function findGoodNumber(numbers) {  if (numbers.length === 0) {    return $q.reject();  } else {    return isGood(numbers.shift()).catch(function() {      return findGoodNumber(numbers);    });  }}

maybe non-recursive?

You can formulate a loop that chains lots of then calls, however recursion is absolutely fine here. If you really wanted the loop, it might look like this:

function findGoodNumber(numbers) {  return numbers.reduce(function(previousFinds, num) {    return previousFinds.catch(function() {      return isGood(num);    });  }, $q.reject());}

This is however less efficient, as it always looks at all numbers. The "recursive" version will evaluate it lazily, and only do another iteration if the current number was not good.

maybe faster?

You can fire all isGood checks in parallel, and wait for the first fulfilled to return. Depending on what isGood actually does and how well that is parallelizable, this might be "better". It potentially does a lot of unnecessary work, though; you may want to use a promise library that supports cancellation.

An example using the Bluebird library, which has a any helper function dedicated to this task:

function findGoodNumber(numbers) {  return Bluebird.any(numbers.map(isGood))}


Here is an alternative solution with a different form of recursion:

function firstGood(arr){    var i = 0;    return $q.when().then(function consume(){        if(i >= arr.length) return $q.reject(Error("No Number Found"));        return isGood(arr[i++]).catch(consume);    });}

It's pretty similar to what Bergi has and it's about the best you can get without implementing a Promise.reduce like some libraries (Bluebird and more recently When) have.


this is my version by simply using array.map function

Demo

angular.module('MyApp', []).run(function($q, $timeout) {  var arr = [3, 9, 17, 26, 89];  findGoodNumber(arr).then(function(goodNumber) {    console.log('Good number found: ' + goodNumber);  }, function() {    console.log('No good numbers found');  });  function findGoodNumber(numbers) {    var defer = $q.defer();    numbers.forEach(function(num){            isGood(num).then(function(){        defer.resolve(num);      });    });    return defer.promise;  }  function isGood(number) {    var defer = $q.defer();    $timeout(function() {      if (number % 2 === 0) {        defer.resolve();      } else {        defer.reject();      }    }, 1000);    return defer.promise;  }});