Javascript 角度-在forEach循环中等待API调用,然后返回数组

Javascript 角度-在forEach循环中等待API调用,然后返回数组,javascript,angularjs,api,Javascript,Angularjs,Api,Angular的异步化有点问题。基本上,我是在循环几张牌。特定两种类型的卡需要API调用,而非这两种类型的卡不需要任何API调用。在循环遍历所有卡之后,返回完成的卡的数组,但我只返回不需要任何API调用的卡 这是我制作的一个关于它工作原理的快速模型: // If color of colorCard is blue, it needs 2 API calls // If color of colorCard is red, it needs 1 API call // If color of c

Angular的异步化有点问题。基本上,我是在循环几张牌。特定两种类型的卡需要API调用,而非这两种类型的卡不需要任何API调用。在循环遍历所有卡之后,返回完成的卡的数组,但我只返回不需要任何API调用的卡

这是我制作的一个关于它工作原理的快速模型:

// If color of colorCard is blue, it needs 2 API calls
// If color of colorCard is red, it needs 1 API call
// If color of colorCard is yellow, it doesn't need an API call
// Pretend for this example that colorCards has one yellow card, one blue card, and two red cards

var buildCards = function() {
  var finishedArray = [];
  var promises = [];
  colorCards.forEach(function(e, i){
    if (e.color === 'blue') {
      promises.push(firstBlueApiCall); 
      var firstBlueIdx = 0;
      promises.push(secondBlueApiCall); 
      var secondBlueIdx = 1;
    } else if (e.color === 'red') {
      promises.push(redApiCall); 
      var redIdx = 0;
    }

    // If card is blue or red, complete API calls before pushing to finishedArray
    if (promises.length > 0) {
        $q.all(promises).then(function(response) {
          if (e.color === 'blue') {
            e.firstBlueData = response[firstBlueIdx];
            e.secondBlueData = response[secondBlueIdx];
          } else if (e.color === 'red') {
            e.redData = response[redIdx];
          }
          finishedArray.push(e);
          promises = [];
        });
    // If card is yellow, push to finishedArray without making any API calls
    } else {
      finishedArray.push(e);
      promises = [];
    }
  })
  return finishedArray;
}

在本例中,返回的finishedArray只包含一张不需要API调用的黄卡,而不是所有四张卡。我如何才能让“return finishedArray”等待红/蓝卡完成API调用?

以下是我如何解决这个问题的:

var promiseFunction = function(card){
  var deferred = $q.defer();
  var localPromises = [];

  if (card.color === 'blue') {
    localPromises.push(blueApiCall1); var firstBlueIdx = promises.length - 1;
    localPromises.push(blueApiCall2); var secondBlueIdx = promises.length - 1;
  } else if (card.color === 'red') {
    localPromises.push(redApiCall); var redIdx = promises.length - 1;
  }

  if (localPromises.length > 0) {
      $q.all(promises).then(function(res) {
        if (card.color === 'blue') {
          card.firstBlueData = res[firstBlueIdx];
          card.secondBlueData = res[secondBlueIdx];
        } else if (card.color === 'red') {
          card.redData = res[redIdx];
        }
        deferred.resolve(card);
      });
  } else {
    deferred.resolve(card);
  }
  return deferred.promise;
}

var buildCards = function() {
  var deferred = $q.defer();
  var finishedArray = [];
  var promises = [];
  colorCards.forEach(function(card, i){
    promises.push(promiseFunction(card));
  });
  $q.all(promises).then(function(finishedCards) {
    deferred.resolve(finishedCards)
  })
  return deferred.promise;
}

我试着让它,所以它的承诺一路下来,它的结果很好。希望这能在将来帮助有类似问题的人。

可以简化
构建卡的功能:

var buildCards = function(colorCards) {
  //var deferred = $q.defer();
  //var finishedArray = [];
  var promises = [];
  colorCards.forEach(function(card, i){
    promises.push(promiseFunction(card));
  });
  //$q.all(promises).then(function(finishedCards) {
  //  deferred.resolve(finishedCards)
  //})
  //return deferred.promise;
  return $q.all(promises);
}
由于
$q.all
方法已返回承诺,因此不需要使用
$q.defer
生成承诺。此外,制造承诺没有正确处理拒绝。如果任何
$q.all
承诺被拒绝,则
$q.defer
承诺将挂起且永远不会解决

这被称为a,应该避免

类似地,可以修改
承诺功能
功能,以避免:

promise的
then
方法总是返回一个新的promise,该promise解析为返回给处理函数的值。此外,如果原始承诺被拒绝,成功处理程序将被跳过,拒绝将沿着链传递到新承诺。这样可以避免错误挂起
$q.defer

还请注意,如果没有承诺使用
$q.all
进行处理,则可以在
$q.when
时使用
创建
cardPromise

因为调用允诺的
.then
方法会返回一个新的派生允诺,所以很容易创建允诺链。可以创建任意长度的链,并且由于一个承诺可以用另一个承诺解决(这将进一步推迟其解决),因此可以在链中的任何点暂停/推迟承诺的解决。这使得实现强大的API成为可能

--


总是连锁反应。避免使用。

JavaScript是单线程的。当函数完成时,它只能返回可用的数据或将来将要实现的待定承诺。
var promiseFunction = function(card){
  //var deferred = $q.defer();
  var localPromises = [];

  if (card.color === 'blue') {
    localPromises.push(blueApiCall1); var firstBlueIdx = promises.length - 1;
    localPromises.push(blueApiCall2); var secondBlueIdx = promises.length - 1;
  } else if (card.color === 'red') {
    localPromises.push(redApiCall); var redIdx = promises.length - 1;
  }

  var cardPromise;
  if (localPromises.length > 0) {
      //$q.all(promises).then(function(res) {
      cardPromise = $q.all(localPromises).then(function(res) {
        if (card.color === 'blue') {
          card.firstBlueData = res[firstBlueIdx];
          card.secondBlueData = res[secondBlueIdx];
        } else if (card.color === 'red') {
          card.redData = res[redIdx];
        }
        //deferred.resolve(card);
        //RETURN value to chain
        return card;
      });
  } else {
      //deferred.resolve(card);
      cardPromise = $q.when(card);
  }
  //return deferred.promise;
  return cardPromise;
}