最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to make a forEach loop wait for each Ajax function to finish - Stack Overflow

programmeradmin6浏览0评论

I have an array of statements and I want to loop through each and submit to the server via an ajax call. I have to make sure each ajax request is executed before the next request is sent, because on the server side code, I am creating a unique key for this array of statements. What happens is before I can mit the first request, the second request es in and I end up have 2 separate keys being created since it sees each of them as a first time request. I can't rely on timeout entirely and the code I have so far, continues with the loop.

function formPostSubmission(form){
    var parts = ['a', 'b', 'c'];
    var i = 0;
    parts.forEach(function(entry) {
        i++;
        datafield ={
            answer:entry,
            displayOrder:i,
            ajaxName:'statementPartialSubmit'
        };
        $.when(submitAjaxData(form, datafield)).then(function succesHandler(data){
            console.log("promise test "+data);
            console.log("Below request ");
        },
        function errorHandler(){
            console.log("Error occurred ");
        })
        console.log("Go for next ");
    });
}

function  submitAjaxData(form, datafield) {
    console.log(" called submitAjaxData  ");
    var loadurl = domainName + "/ajax-call-handler";
    return $.ajax({
        url: loadurl,
        method: "GET",
        data: datafield
    });
}

I was hoping to check response data for a success and then proceed within the loop. But this is how my console prints.

called submitAjaxData
Go for next
called submitAjaxData 
Go for next
promise test  
Below request
promise test 
Below request 

I have an array of statements and I want to loop through each and submit to the server via an ajax call. I have to make sure each ajax request is executed before the next request is sent, because on the server side code, I am creating a unique key for this array of statements. What happens is before I can mit the first request, the second request es in and I end up have 2 separate keys being created since it sees each of them as a first time request. I can't rely on timeout entirely and the code I have so far, continues with the loop.

function formPostSubmission(form){
    var parts = ['a', 'b', 'c'];
    var i = 0;
    parts.forEach(function(entry) {
        i++;
        datafield ={
            answer:entry,
            displayOrder:i,
            ajaxName:'statementPartialSubmit'
        };
        $.when(submitAjaxData(form, datafield)).then(function succesHandler(data){
            console.log("promise test "+data);
            console.log("Below request ");
        },
        function errorHandler(){
            console.log("Error occurred ");
        })
        console.log("Go for next ");
    });
}

function  submitAjaxData(form, datafield) {
    console.log(" called submitAjaxData  ");
    var loadurl = domainName + "/ajax-call-handler";
    return $.ajax({
        url: loadurl,
        method: "GET",
        data: datafield
    });
}

I was hoping to check response data for a success and then proceed within the loop. But this is how my console prints.

called submitAjaxData
Go for next
called submitAjaxData 
Go for next
promise test  
Below request
promise test 
Below request 
Share Improve this question edited Nov 13, 2018 at 20:46 Udi 30.5k9 gold badges105 silver badges133 bronze badges asked Nov 13, 2018 at 6:41 RacheRache 2171 gold badge7 silver badges22 bronze badges 0
Add a ment  | 

4 Answers 4

Reset to default 3

use promises :

 var promises = [];
 for (var i = 0; i < $total_files; i++) {
 // jQuery returns a prom 
   promises.push($.ajax({
  /* your ajax config*/
  }))
 }

Promise.all(promises)
.then(responseList => {
 console.dir(responseList)
 })

you could use this solution by using await , for example :

for (let f of files) {
    await $.ajax({/* your ajax config*/ });
 }
async: false 

is the best option in your case

I wrote this function, PromiseAllSeq, to execute an array of promises sequentially.

You can pass a callback as the second parameter if you choose, but given your issue i've put together a working demo based on your code.

console.clear();
/**
 *  Promises will wait for each other and will return any[].
 *  If a promise is rejected it will stop.
 *  @param arr - (Promise<any> | ()=>Promise<any>)[] - Accepts promise or a function that returns a promise
 *  @param callback(response, index) - If callback 'returns' it will overwrite the current response. Useful for changing the response.
 *  @returns any[]
 */
const PromiseAllSeq = (arr, callback) => {

  let result = [];

  if (typeof callback !== 'function') {
    callback = () => {};
  }

  const rec = (arr) => {

    return new Promise((resolve, reject) => {

      if (arr.length) {

        (typeof arr[0] === 'function' ? arr[0]() : arr[0]).then(res => {

          let cb = callback(res, result.length);

          result = result.concat(typeof cb !== 'undefined' ? cb : res);

          arr.splice(0, 1);

          resolve(arr.length ? rec(arr) : result);

        }).catch(err => {

          reject(err);

        })

      } else {

        resolve(result);

      }

    })

  }

  return rec(arr);

}

function succesHandler(data, index) {

  // Here i can alter 'data'
  data['finishedPromiseNr'] = index;

  console.log("promise test ", data, index);

  console.log("Go for next ");

  return data;

}

function errorHandler(err) {
  console.log("Error occurred ", err);
}

function submitAjaxData(form, datafield) {
  console.log("called submitAjaxData  ", datafield);
  //var loadurl = domainName + "/ajax-call-handler";

  // Mock some requests with delayed responses
  // https://reqres.in/#console
  var loadurl = "https://reqres.in/api/users?delay=" + datafield.fakeDelay;
  return $.ajax({
    url: loadurl,
    method: "GET",
    data: datafield
  });
}

function formPostSubmission(form) {
  var parts = ['a', 'b', 'c'];
  var i = 0;
  let poll = [];
  parts.forEach(function(entry) {
    i++;

    // 'datafield' was not assigned with var or let
    // Reassigning it on each loop will allow 'datafield' to pass in the anonymous function below
    let datafield = {
      answer: entry,
      displayOrder: i,
      ajaxName: 'statementPartialSubmit',
      fakeDelay: parts.length - i
    };

    // Wrong: submitAjaxData is called, that means, the requests are sent immediately.
    // poll.push( $.when(submitAjaxData(form, datafield) );

    // Correct: Wrap and return $.when into a function otherwise 'submitAjaxData' will trigger the requests
    poll.push(() => $.when(submitAjaxData(form, datafield)));

  });

  PromiseAllSeq(poll, succesHandler).then(responseList => {

    console.log('final response');
    console.log(responseList);

  }).catch(errorHandler)


}

formPostSubmission(null);
<script src="https://code.jquery./jquery-3.3.1.min.js"></script>

发布评论

评论列表(0)

  1. 暂无评论