如何使用 .map() 将承诺的结果分配给数组元素?

How to assign the result of a promise to array elements using .map()?

我在这里使用 AngularJS,但如果您有更通用的答案,我会很高兴知道。

我有一个包含 id 的元素数组

myArray = [{
  id: 0,
  foo: "foo"
}, {
  id: 1,
  bar: "bar"
}]

以及使用这些 id 询问信息的服务,它以一个信息对象(用于请求)和两个回调,一个用于成功,一个用于错误(都不是必需的)作为参数。

Service.getInformations({id: 1}, onSuccess, onError)

我想做的是这样的:

myArray.map(function (element){
  Service.getInformations({id: element.id}, function(data) {
    return data; // here is the issue
  })
});

这里的问题是我在服务回调函数中而不是在地图回调函数中返回数据。我正在努力寻找一些好的方法。

Promise.all(myArray.map(item => new Promise((resolve, reject) => {
  Service.getInformations({id: item.id}, resolve, reject)
}).then((resultArray) => {
  //reduce result
}).catch((errorArray)=> {
  //reduce error
})

链接异步函数是一个棘手的老问题。这是在 Vanilla Javascript(有或没有 Angular)中的一种方法:

var myArray = [
  {
    id: 0,
    foo: "foo"
  },
  {
    id: 1,
    bar: "bar"
  }
];

var asyncChain = function(myFunction){
  var nextThingToDo = function(){
    myFunction(nextThingToDo);
  }
  nextThingToDo();
}
// In this example, myFunction is getArrayItemInfo
// nextThingToDo is goToNextArray Item
// This is how Express.js and Node do things
// Yes, nextThingToDo is calling itself
// If this seems weird, it's because it is. Yay, Javascript.

var index = 0;
var getArrayItemInfo = function(goToNextArrayItem){
  if(index < myArray.length){
    Service.getInformations({id: index}, function(data){
      myArray[index].data = data; // You can do something with the data here
      index += 1;
      goToNextArrayItem(); // Move on to the next item when the asynchronous part is done
      // Without this, execution would stop here
    });
  }
}

asyncChain(getArrayItemInfo);

这是一个简单的示例,您可以在没有 Angular 的情况下尝试:

var myArray = ["One sec", "Two secs", "Three secs", "...and that's all."];
var asyncChain = function(myFunction){
  var next = function(){
    myFunction(next);
  }
  next();
}
var index = 0;
var getArrayItemInfo = function(goToNextArrayItem){
  if(index < myArray.length){
    setTimeout(function(){
      document.write(myArray[index] + "<br />");
      index += 1;
      goToNextArrayItem();
    }, 1000);
  }
}
asyncChain(getArrayItemInfo);

您可以这样做,使用 angular 上的内置 $q 服务。

您可以遍历元素,调用服务和 return 承诺,仅当所有异步操作完成时才执行回调。

在这种情况下,回调从各自的调用中获取一组结果。

var app = angular.module("sampleApp", []);

app.controller("sampleController", ["$scope", "$q", "sampleService",
  function($scope, $q, sampleService) {
    var randomArray = [1, 2, 3, 4, 5, 6];

    var promisesArray = randomArray.map((input) => {
      return sampleService.getInformations(input)
    });

    $q.all(promisesArray).then(function(outputArray) {
      console.log("Results Array");
      console.log(outputArray);
    });
  }
]);

app.service("sampleService", function() {
  this.getInformations = function(value) {
    var promise = new Promise(function(resolve, reject) {
      setTimeout(function() {
        value = value * 2;
        resolve(value);
      }, 1000);
    });

    return promise;
  };
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js"></script>
<div ng-app="sampleApp">
  <div ng-controller="sampleController">

  </div>
</div>