How to make a LOOP run according to the return of a Promise?

3

How can I make my loop wait for the return of a promise?

Let's say I have the following code:

for (var i = 0; i < 10; i ++) {
   // algumalógica
   fazAlgumaCoisa(array[i]);
}

var fazAlgumaCoisa = function(obj) {
   $http.get(url).then(function success(response) {

   }, function error(response) {

   });
}

My question is: how do I do it for me to wait for the return of this call http ?

    
asked by anonymous 29.06.2016 / 14:51

4 answers

6

I put a response with an idea that nobody has mentioned yet, and that I think is the best option. Using Promise.all .

When you describe what you need "before touching, make sure all files have been read in memory." this is exactly what Promise.all does.

Passing an array of Promises to this Promise.all expects all to be resolved and returns a% of the method of success an array with the values of the past Promises. If you pass static values (Strings, Objects, or other variables that are not asynchronous) it uses it, calling Promise immediately. This is why Promise.resolve accepts a mixed array, with Promises or not.

A simple example would look like this: link , what you need in your case would look something like this:

var urls = ['/pasta/a', '/pasta/b' /* etc... */ ];

function get(url, i) {
    return $http.get(url); <-- isto será o que queres
}

Promise.all(urls.map(get)).then(function(res) {
    console.log(res); // aqui "res" é uma array com a resposta de cada "$http.get", na mesma ordem da array "urls".
}, function() {
    console.log('Algo falhou!');
});
    
29.06.2016 / 19:50
5

You can use Queues .

Prepare a collection containing the items you want to process, and run individual processes until the queue runs out.

One of the advantages of this pattern is that it allows you to add new items to the queue even while running the main loop.

Below is an example of a First In, First Out serial queue - or first, exit first):

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

app.controller("filaController", function($scope, $http) {

  var that = this;
  
  // Itens iniciais a serem processados
  this.ZipCodesAPesquisar = [77379, 77380, 77381];

  this.processaProximaEntrada = function(){
    //Existem itens na minha fila? Se sim, processe o primeiro.
    if (that.ZipCodesAPesquisar.length > 0){
      that.processaFila(that.ZipCodesAPesquisar[0]);
      return;
    }
  }

  this.processaFila = function (unidade){

    this.removeDaFila = function(unidade){
      //Localiza a posição da unidade na fila
      var indice = that.ZipCodesAPesquisar.indexOf(unidade);

      //Caso encontrado, remova:
      if (indice != -1) {
        that.ZipCodesAPesquisar.splice(indice, 1);
        
        // Verifique se ainda existem itens na fila.
        that.processaProximaEntrada();
      }
    }

    console.log("Processando " + unidade);

    $http.get('http://maps.googleapis.com/maps/api/geocode/json?address=' + unidade + '&sensor=true')
    .then(function success(response) {
      console.log(response.data.results[0].formatted_address);
      that.removeDaFila(unidade);
    }, function error(response) {
      that.removeDaFila(unidade);
    });    
  };

  //Inicializa processamento da fila
  this.processaProximaEntrada();

})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script><divng-app="exemplo" ng-controller="filaController">
</div>
    
29.06.2016 / 15:55
3

You can work with recursion. You use an anonymous named function to reference itself, and if it is within the conditions, you run it again. The condition placed avoids infinite recursion.

var exemplo = function next(i) {


    $http.get(url).then(function success(response) {

        next.loop >=  i && next(++i);

    }, function error(response) {

        next.loop >= i && next(++i);
    });
}

exemplo.loop = 10;

exemplo(0);

In the above case, while the property of the loop function is greater than i , recursion will be applied. The anonymous function named internally of next will be executed only when success or error is called by $http.get .

I made a small example for you to understand how this works. It is a function that writes a value in HTML . It will write as long as the value of loop is greater than i . It's the same case above, but applied with setTimeout to you understand the logic of my recursion:

var counter = function _fn(i) {

    _fn.loop > i && setTimeout(function () { 
    	_fn(++i) 
         document.body.innerHTML = i;
    }, 1000);
}

counter.loop = 10;

counter(0)
    
29.06.2016 / 15:08
3

Similar to @WallaceMaxters answer , but in practice with script you are using .

function loopPromise(url, start, end, callSuccess, callError){

    $http = new $http(url); // Gera a promise para a url solicitada 

    var func = function(obj){
        $http.get().then(function success(response){
            if(typeof callSuccess == 'function'){
                callSuccess('loaded'+start);  // chama sua função de sucesso, caso tenha sido definida
            }
            if(start++ < end){
                func(); // gera o loop ate start ser = a end
            }
        }, function(response){
            if(typeof callError == 'function'){
                callError(response); // chama sua função de erro, caso tenha sido definida, e não propaga mais o loop
            }
        });
    }
    func();
}

url = 'https://code.jquery.com/jquery-3.0.0.js';
loopPromise(url, 0, 10, function(response){
    console.log(response);
}, function(response){
    console.log(response);
});
    
29.06.2016 / 15:59