【问题标题】:How to make a forEach loop wait for each Ajax function to finish如何让 forEach 循环等待每个 Ajax 函数完成
【发布时间】:2019-04-15 22:40:09
【问题描述】:

我有一个array 的语句,我想遍历每个语句并通过ajax 调用提交给server。我必须确保在发送下一个请求之前执行每个ajax 请求,因为在server 侧代码上,我正在为此array 语句创建一个unique key。发生的事情是在我提交第一个请求之前,第二个请求进来,我最终创建了 2 个单独的密钥,因为它将每个密钥都视为第一次请求。我不能完全依赖超时,我到目前为止的代码继续循环。

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
    });
}

我希望检查响应数据是否成功,然后在循环中继续。但这就是我的console 的打印方式。

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

【问题讨论】:

    标签: javascript jquery ajax loops


    【解决方案1】:

    使用承诺:

     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)
     })
    

    【讨论】:

    • 感谢您回复莎丽。我刚试过这个。你能解释一下这应该如何工作吗?我看到循环获取第一个元素,然后在 ajax 调用之后立即打印控制台消息。但是我在 ajax 请求中添加了一个时间参数,我看到两个请求都添加了相同的时间。
    • 这并不能保证请求是按顺序发送的!
    • 是的,我又做了一些测试,但没有按顺序发送。
    • Promise.all 一次返回所有已解决的承诺,或者如果一个承诺被拒绝则失败。正如@Fitzi 所说,它不能保证它们会按顺序解决
    • 我发布另一个解决方案
    【解决方案2】:
    async: false 
    

    是您的最佳选择

    【讨论】:

    • 虽然这段代码 sn-p 可以解决问题,including an explanation 确实有助于提高您的帖子质量。请记住,您是在为将来的读者回答问题,而这些人可能不知道您提出代码建议的原因。
    • async: false 在几年前因为负面的用户体验而被弃用。
    【解决方案3】:

    您可以通过 await 使用此解决方案,例如:

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

    【讨论】:

      【解决方案4】:

      我编写了这个函数,PromiseAllSeq,用于按顺序执行一组承诺。

      如果您愿意,您可以将回调作为第二个参数传递,但鉴于您的问题,我已经根据您的代码组合了一个有效的 demo

      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);
      &lt;script src="https://code.jquery.com/jquery-3.3.1.min.js"&gt;&lt;/script&gt;

      【讨论】:

        猜你喜欢
        • 2021-04-23
        • 1970-01-01
        • 1970-01-01
        • 2014-08-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-11-10
        相关资源
        最近更新 更多