Wait for a for each with ajax requests to finish to continue

7

I'm doing forEach in a array but this loop has an ajax request inside for each repetition and I need to wait until all the ajax are ready to continue ordering the array that is filled with these requests, this It's my code.

var getTables = (scoreQ, scoreE) => {

    var arr = [];

    Object.keys(scoreQ).forEach(key => {
        var range;
        var scoreDivide = scoreE[key] / 3;
        if (parseFloat(scoreQ[key]) < parseFloat(scoreDivide)) {
            range = "bajo";
        } else if ((parseFloat(scoreQ[key]) >= parseFloat(scoreDivide)) && (parseFloat(scoreQ[key]) <= parseFloat(scoreDivide * 2))) {
            range = "medio";
        } else if ((parseFloat(scoreQ[key]) >= parseFloat(scoreDivide * 2)) && (parseFloat(scoreQ[key]) <= parseFloat(scoreDivide * 3))) {
            range = "alto";
        }

        //console.log(key, range, scoreQ[key], scoreE[key])

        $.ajax({
            type: "post",
            url: "php/resQuery/tables.php",
            data: {
                valuebook: key,
                range
            },
            dataType: "json",
            success: response => {
                var doc = response;
                arr.push('<tr> <td>${doc.table.valuebook.replace(/_/gi, " ")}</td> <td>${parseFloat(scoreQ[key]).toFixed(1)}</td> <td>${doc.table.rangeT}</td> <td>${doc.table.descriptionp}</td> <td>${doc.table.descriptions}</td> </tr>');
            }
        });
    })

    arr.sort()
    arr.forEach(element =>{
        console.log(element);
    })

    }

How can I make the second forEach wait until the first one finishes making all the requests?

I tried to put a promise type done and then after the first but it did not work

    
asked by Emiliano Pamont 13.09.2018 в 18:50
source

4 answers

4

You can create a counter and a setInterval that checks until the counter is equal to the length of your first array. Something like this:

var getTables = (scoreQ, scoreE) => {

var arr = [];
var cont = Object.keys(scoreQ).length;
var i = 0;
Object.keys(scoreQ).forEach(key => {
    var range;
    var scoreDivide = scoreE[key] / 3;
    if (parseFloat(scoreQ[key]) < parseFloat(scoreDivide)) {
        range = "bajo";
    } else if ((parseFloat(scoreQ[key]) >= parseFloat(scoreDivide)) && (parseFloat(scoreQ[key]) <= parseFloat(scoreDivide * 2))) {
        range = "medio";
    } else if ((parseFloat(scoreQ[key]) >= parseFloat(scoreDivide * 2)) && (parseFloat(scoreQ[key]) <= parseFloat(scoreDivide * 3))) {
        range = "alto";
    }

    //console.log(key, range, scoreQ[key], scoreE[key])

    $.ajax({
        type: "post",
        url: "php/resQuery/tables.php",
        data: {
            valuebook: key,
            range
        },
        dataType: "json",
        success: response => {
            i++;
            var doc = response;
            arr.push('<tr> <td>${doc.table.valuebook.replace(/_/gi, " ")}</td> <td>${parseFloat(scoreQ[key]).toFixed(1)}</td> <td>${doc.table.rangeT}</td> <td>${doc.table.descriptionp}</td> <td>${doc.table.descriptions}</td> </tr>');
        }
    });
})
var inter = setInterval(function(){ 
  if (i == cont) {
    arr.sort()
    arr.forEach(element =>{
      console.log(element);
    }) }, 1000);
    clearInterval(inter);
  }
} 
    
answered by 13.09.2018 в 19:02
2

Create a small code so you can guide yourself. The first thing I did was create a variable item where I store my array , then pass that array as an argument to the processArray function, if you look at it an async function and within a for instead of a forEach , the for calls a function > async call promise which is a kind of promises handler and in turn calls a ajax function where you would place your ajax strong> and he would return the response to promise and the turn to processArray . In processArray once the answer is received you can evaluate if the ajax was executed correctly or not, this is the code:

var items = [{item: 1, desc: "item1"}, {item: 2, desc: "item2"}, {item: 3, desc: "item3"}];

const ajax = (item) => {
  
  return new Promise(resolve => 
    setTimeout(resolve(item.desc),2000)
  );
  
}

const promesa = async(item) => {
  
  console.log("Llamando al ajax")
  let respuesta = await ajax(item);
  console.log("Ajax respondio = "+respuesta);
  return respuesta;
  
}

const procesarArray = async (items) => {

  for(const item of items){
    let respuesta = await promesa(item)
    console.log(respuesta);
  }
  
  console.log("listo");
  
}

procesarArray(items);
    
answered by 13.09.2018 в 21:57
1

If you want to save it in the arr array in the same order in which you execute the ajax then you can use the forEach indexes

var getTables = (scoreQ, scoreE) => {

var arr = [];

// función sincrona para lectura de array
var SyncArray = (array, index) => {

}

var ArraydeAjaxs = [];

Object.keys(scoreQ).forEach((key, index) => {
    var range;
    var scoreDivide = scoreE[key] / 3;
    if (parseFloat(scoreQ[key]) < parseFloat(scoreDivide)) {
        range = "bajo";
    } else if ((parseFloat(scoreQ[key]) >= parseFloat(scoreDivide)) && (parseFloat(scoreQ[key]) <= parseFloat(scoreDivide * 2))) {
        range = "medio";
    } else if ((parseFloat(scoreQ[key]) >= parseFloat(scoreDivide * 2)) && (parseFloat(scoreQ[key]) <= parseFloat(scoreDivide * 3))) {
        range = "alto";
    }

    //console.log(key, range, scoreQ[key], scoreE[key])

    ArraydeAjaxs.push(
        $.ajax({
        type: "post",
        url: "php/resQuery/tables.php",
        data: {
            valuebook: key,
            range
        },
        dataType: "json",
        success: response => {
            var doc = response;
            arr[index] = '<tr> <td>${doc.table.valuebook.replace(/_/gi, " ")}</td> <td>${parseFloat(scoreQ[key]).toFixed(1)}</td> <td>${doc.table.rangeT}</td> <td>${doc.table.descriptionp}</td> <td>${doc.table.descriptions}</td> </tr>';
        }
    });
})
    )

$.when(...ArraydeAjaxs).done(() =>{

    arr.forEach(element =>{
        console.log(element);
    })
});

}
    
answered by 13.09.2018 в 19:19
1

The ideal thing is to mask the calls to ajax with promises and call Promise.all, which will execute the callback until they are all finished, in this way you do not return the ajax blocking calls for the user. An example would be:

function getTables(scoreQ, scoreE){
  var promises = [];
  Object.keys(scoreQ).forEach(key => {
    var promise = new Promise((resolve, reject) => {
    // las promesas enmascaran los datos asíncronos que necesitamos
      $.ajax({
        type: "GET",
        url: "https://dog.ceo/api/breeds/image/random",
        dataType: "json",
        success: resolve, //termino de promesa
        error: reject //si ocurre algún error.
      });
    });
    promises.push(promise);
  })

  Promise.all(promises).then((arr) => {
    arr.sort()
    arr.forEach(element =>{
      //aquí se puede insertar ya en el dom
      // element es lo que recibes con cada llamada ajax...
      console.log(element);
    })
  });
}

getTables({a:1, b:2});

Modify the initial code so that you can see its operation when interacting with another API. CodePen .

    
answered by 13.09.2018 в 20:14