来自 for 循环内的 AJAX 链中最后一个 AJAX 请求的返回值

Posted

技术标签:

【中文标题】来自 for 循环内的 AJAX 链中最后一个 AJAX 请求的返回值【英文标题】:Return value from last AJAX request in AJAX chain that is inside a for loop 【发布时间】:2016-07-06 15:32:00 【问题描述】:

我有一个for 循环,并且在一次迭代中(某事)我需要发出四个 AJAX 请求,然后等到最后一个请求的结果。

jQuery Deferred - getting result of chained ajax calls chaining jquery .when().then() in a loop with fixed end of chain call How to make for loop wait until Async call was successful before to continue

现在我只知道如何将数据从先前的承诺传递给另一个承诺,例如in this cool answer,但我需要将最后一次 AJAX 调用的值返回到外部数组(并等到最后一次 AJAX 调用完成) 然后在循环外继续其他函数。

                attaches.forEach(function(attach)) 
                    if(attach.val == "val1")
                        attachments.push(attach.val1);
                    
                    if(attach.val == "val2")
                         attachments.push(attach.val2);
                    
                    if(attach.val == val3)
                       function func1()
                           var params = [param1,param2];
                           return   $.post(api, params.join('&'))
                       
                       function func2()
                           console.log('1111');
                           return new Promise(function(resolve, reject)) 
                               var xhr = new XMLHttpRequest();
                               xhr.onload = function () 
                                   resolve(xhr.response);
                                
                               xhr.open('GET', img_src);
                               xhr.responseType = 'blob';
                               xhr.send();                           
                           );
                       
                       function uploadPhoto(upload_url, bulbSend)
                               console.log('<Del><F7>              function uploadPhoto');
                           return $.ajax(
                               url: upload_url, 
                               type: 'POST',
                               data: bulbSend,
                               dataType: 'json',
                               processData: false,
                               contentType: false,
                           );                   
                        
                       function saveResult(params)
                          
                           return $.post(api, params.join('&'))
                       
                           func1().then(fun1hand()).then(console.log('a32w436bya3b7naua'));
                       function fun1hand()
                           return function(dat4a) 
                               return  func2().then(func2hand(dat4a));
                           ;
                       
                       function func2hand(dat4a)
                           console.log('2222');
                           return function(datums)
                               console.log('3333');
                               var upload_url = dat4a.upload_url;
                               console.log('UPLOAD__URL BEFORE PROMISE  '+upload_url);
                               var bulbSend = new FormData();
                               bulbSend.append('file1', datums, 'file.jpg');
                               
                 return uploadPhoto(upload_url,bulbSend).then(func3hand());
                           
                       
                       function func3hand()
                         return  function(data2)
                             var params = [data2.param1, data2.param2, data2.param3];
                             return saveResult(params).then(pushToAttachmentsHandler());
                         
                       
                       function pushToAttachmentsHandler()
                           return function(data3)
                               console.log('PUSUSUSUSSUSUSUUSUS PUSHHHHHHH PUSH DA BAUTTON');
                               console.log(attachments);
                               return pushDat(data3).then(console.log(attachments));
                           
                       
                       function pushDat(data3)
                           console.log('1111');
                           return new Promise(function(resolve, reject) 
attachments.push(data3.param3+"_"+data3.param1));
                           console.log('11111111111');
                           );
                       
                        
                    
                );

循环外的函数在 console.log('3333') 内的 Promise 之前开始其 console.logs...但它们需要等待直到循环内的 AJAX 调用完成并且循环完成。

现在我需要在超时后重复 AJAX,如果它被拒绝(每秒服务器请求限制) - 我如何在我的代码中为原生 XMLHttpRequest() 设置它,这是在 promise 中,对于 jQuery AJAX 调用是退了吗?

【问题讨论】:

@Roland Starke 我的代码很脏,只是以某种方式编辑 【参考方案1】:

看起来很简单,对于异步和同步 ajax 请求,您都可以使用:

var myVar;

yourLoop(function() 
    yourAjax(function(result) 
        myVar = result;
    );
);

在 ajax 成功(完成)回调中更改变量值

UPD:

如果您需要对最后一个结果进行回调,我可能会建议您使用这个 hackly 选项:

var myVar, timeout;

yourLoop(function() 
    yourAjax(function(result) 
        myVar = result;

        clearTimeout(timeout);
        timeout = setTimeout(function() 
            // do something . . .
            console.log('last result', myVar);
        , 1000);
    );
);

注意:将 1000 更改为预期的最大响应时间

【讨论】:

【参考方案2】:

回调或承诺能够处理这种异步控制流...

假设你原来的非工作代码是……

for(var i=0; i < 10; i++)
    $.get('http://example.com/rest/users/'+i);
    $.get('http://example.com/rest/posts/'+i);
    $.get('http://example.com/rest/comments/'+i);
    $.get('http://example.com/rest/events/'+i);

回调...

var i = 1;

getSet(repeater);

// define a repeater function to be used as recursive callback
function repeater ()
    // increment counter
    i++;
    // if we still have items to process, get another set
    if(i < 10)
        getSet(repeater);
    


function getSet(cb)
    // define queue
    var counter = 0;
    // make four api calls, defining success callbacks, which call the
    // originally passed callback if the counter reaches 0. Increment counter before each request. This means the callback fires only for the last result
    counter++;
    $.get('http://example.com/rest/users/'+i, handleSuccess);
    counter++;
    $.get('http://example.com/rest/posts/'+i, handleSuccess);
    counter++;
    $.get('http://example.com/rest/comments/'+i, handleSuccess);
    counter++;
    $.get('http://example.com/rest/events/'+i, handleSuccess);

    function handleSuccess(data)
        // do something with data
        --counter || cb();
    

这种模式的工作原理是这样的......

getSet 第一次被调用,repeater 函数预计会在所有异步请求完成后被调用。 getSet 函数在进行异步调用时递增堆栈,并在异步回调中递减,当堆栈恢复为零并且队列中没有更多异步作业时调用repeater。然后repeater 回调重复整个过程,调用getSet 并将自身作为回调传递,直到满足条件。

【讨论】:

为什么不 cb();在第一个异步回调中运行?最后一个ajax调用中'or'运算符的含义首先与它不同吗?我需要等待来自 prev ajax 的数据来调用下一个...我需要 ajax 链只有当循环中出现某些东西时,如果迭代有东西,不需要 ajax > 它只是将数据推送到外部数组中...我认为我不明白你的好答案的概念 好的,所以如果您遇到的问题是代码有时是异步的,有时是同步的 - 那么只需将其编码为一直是异步的,当您需要 simply push 时只需触发立即使用数据回调,而不是在 ajax 回调中。这有帮助吗? 我需要以前的 ajax 请求中的值来跟随类似这样的 ajax ( $.get('example.com/+i', function(data1) --counter || cb(); ); $ .get('example.com/+data1.something', function(data2) ... 对数据 1 和数据 2 做一些事情 .... --counter || cb(); ); 并分享到最后 ... i需要在下一个之前等待来自第一个的请求。但现在我不明白 --counter || cb(); 语句......在你的例子中请求应该等到上一个?为什么 var i = 1; 我在link, link,link 找到了一些相关信息,但为什么是 cb();当计数器第一次递减时不执行?因为第一次计数器== 0 ...?您的代码会在下一个之前提供来自第一个 ajax 的等待请求吗?对不起我的愚蠢问题 ajax 成功回调比周围的代码发生得晚得多。它们只有在成功满足 ajax 请求后才会执行。在任何成功回调减少它之前,计数器会增加四次。我更新了答案,希望能让你更清楚

以上是关于来自 for 循环内的 AJAX 链中最后一个 AJAX 请求的返回值的主要内容,如果未能解决你的问题,请参考以下文章

课堂练习找水王02

强制Chrome在TLS期间发送链中的所有证书

js 如何保存循环内的变量,然后循环外使用这个变量?

来自单元格的 Matlab 图例,用于使用 for 循环创建的绘图

如何避免循环内的数据丢失

如何在节点 js 中正确使用等待/异步与 for 循环