How to assign the result of a promise to array ele

2019-08-01 08:28发布

问题:

I am using AngularJS here, but if you have a more generic answer I’ll be glad to know about it.

I have an array of elements containing ids

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

And a service to ask informations using those ids, which take as arguments an object of informations (for the request), and two callbacks, one for success and one for error (both are not required).

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

What I would like to do is something like this:

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

The issue here is that I am returning data in service callback function and not in map callback function. I am struggling to find some good way to do it.

回答1:

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


回答2:

Chaining asynchronous functions is a tricky old problem. Here's a way of doing it in Vanilla Javascript (with or without 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);

Here's a simple example that you can try without 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);



回答3:

You could do something like this, using built in $q service on angular.

You can iterate over the elements, make a call to the service and return a promise and execute the callback only when all async operations are complete.

In this case callback takes an array of results from their respective calls.

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>