循环内的Ajax调用需要同步

时间:2022-04-10 05:06:54

I have a coding issue where I want to loop thru and call an ajax call but I dont want another request to be sent until the first one is complete. I have tried setting it to asyc = false and adding an onsuccess callback. But it seems like the loop is continuing to run which gives me responses out of order and parallel requests.

我有一个编码问题,我想循环通过并调用ajax调用但我不希望在第一个请求完成之前发送另一个请求。我已经尝试将其设置为asyc = false并添加onsuccess回调。但似乎循环继续运行,这给了我无序和并行请求的响应。

// This function is used to generate a numeric val and passes it along in the success callback

//此函数用于生成数字val并在成功回调中传递它

  function duplicateOmsid(totalAmount, omsid) {
var url = '/portal/GetBulkCopyAmountServlet';
var errorString;


new Ajax.Request(
url, {
    method: 'post',
    parameters: {
        totalAmount: totalAmount,
        omsid: omsid
    },        
    async: false,
    onSuccess: function(transport) {
        dataResponse = transport.responseText.evalJSON();
          createWorkflow(totalAmount, omsid, dataResponse);


    },

.....

// Function used to loop thru and call the duplicate workflow ajax call

//用于循环的函数,并调用重复的工作流ajax调用

function createWorkflow(totalAmount, omsid, bulkAmount) {
            var amountProccessed = 0; 
            for( i = 0; amountProccessed < totalAmount; i++ ) {  // Loop through source
                var duplicateAmt;

                if (totalAmount < 11){
                    duplicateAmt = totalAmount
                }else{
                     duplicateAmt = amountProccessed + dataResponse < totalAmount ? dataResponse : totalAmount - amountProccessed
                }


           duplicateWorkflow(totalAmount, omsid, duplicateAmt, amountProccessed);
           amountProccessed += bulkAmount;
    }
     }

// Function used to create the workflow ajax call - the success handler is updating the user.

//用于创建工作流ajax调用的函数 - 成功处理程序正在更新用户。

 function duplicateWorkflow( totalAmount, omsid, bulkAmount, amountProccessed){
        amountProccessed += bulkAmount;
        var url = '/portal/CreateWorkFlowServlet';
        var errorString;
        new Ajax.Request(
        url, {
            method: 'post',     
            parameters: {
                totalAmount: totalAmount,
                omsid: omsid,
                bulkAmount: bulkAmount
            },  
            async: false,
            onSuccess: function(transport) {

             var div = document.getElementById('progress');

         if( amountProccessed > totalAmount){
             div.innerHTML = totalAmount + ' out of ' + totalAmount + ' Processed ' ;

             alert (totalAmount + 'Items successfully duplicated  ')
         }else{
             div.innerHTML = amountProccessed + ' out of ' + totalAmount + ' Processed ' ;
         }
            },

            onFailure: function(e) {
                }
            },

            onException: function(e) {
                }
            },

        });
 }

1 个解决方案

#1


3  

As a rule of thumb, the way to sequentialize async code using raw Javascript is to use recursion instead of a for loop.

根据经验,使用原始Javascript顺序化异步代码的方法是使用递归而不是for循环。

var urls = [ /*...*/ ];

function loop(i, onDone){
    if(i >= urls.length){
        //base case
        onDone( theResultOfProcessingTheAjaxRequests );
    }else{
        Ajax.Request(urls[i], {
            onsuccess: function(){
                loop(i+1, onDone);
            }
        });
    }
}

loop(0, function(result){
    console.log("all done");
});

Note that I converted i to a function parameter, to keep it scoped to the looping function. If you wanted, you could declare it outside, just like you did in the for loop:

请注意,我将i转换为函数参数,以使其作用于循环函数。如果你愿意,你可以在外面声明它,就像你在for循环中所做的那样:

var urls = [ /*...*/ ];
var i = 0;

function loop(onDone){
   //...
   i = i+1;
   loop(onDone);
}

Additionally, I added an "onDone" callback to the looping function to help the async code look a bit more like the sync version. The idea is that by using a return callback, the loop function doesn't need to know what function called it and where it should jump to after its done its job - in the end, calling onDone(x) is a bit similar to doing return x. Of course, you could have hardcoded the return function if you wanted.

另外,我在循环函数中添加了一个“onDone”回调,以帮助异步代码看起来更像同步版本。我们的想法是,通过使用返回回调,循环函数不需要知道调用它的函数以及它在完成其工作后应该跳转到的位置 - 最后,调用onDone(x)有点类似于执行返回x。当然,如果你愿意,你可以硬编码返回功能。

function afterAjax(){
    console.log("all done");
}

function loop(){
    if(i >= urls.length){
       afterAjax();
    }
    //...
}

loop();

Finally, coding recursive loops like this is a bit annoying and there are many libraries out there that provide functions to encapsulate these hight level sequentialization and parallelization patterns. In particular, error handling (try-catch) is specially hard to do by hand with callbacks. If you are doing any more non-tricial Async stuff I would highly recommend looking into some of these libraries.

最后,像这样的编码递归循环有点烦人,并且有许多库提供了封装这些高级序列化和并行化模式的函数。特别是,错误处理(try-catch)特别难以通过回调手动完成。如果你正在做任何更多的非特里异步的东西,我强烈建议你看一些这些库。

#1


3  

As a rule of thumb, the way to sequentialize async code using raw Javascript is to use recursion instead of a for loop.

根据经验,使用原始Javascript顺序化异步代码的方法是使用递归而不是for循环。

var urls = [ /*...*/ ];

function loop(i, onDone){
    if(i >= urls.length){
        //base case
        onDone( theResultOfProcessingTheAjaxRequests );
    }else{
        Ajax.Request(urls[i], {
            onsuccess: function(){
                loop(i+1, onDone);
            }
        });
    }
}

loop(0, function(result){
    console.log("all done");
});

Note that I converted i to a function parameter, to keep it scoped to the looping function. If you wanted, you could declare it outside, just like you did in the for loop:

请注意,我将i转换为函数参数,以使其作用于循环函数。如果你愿意,你可以在外面声明它,就像你在for循环中所做的那样:

var urls = [ /*...*/ ];
var i = 0;

function loop(onDone){
   //...
   i = i+1;
   loop(onDone);
}

Additionally, I added an "onDone" callback to the looping function to help the async code look a bit more like the sync version. The idea is that by using a return callback, the loop function doesn't need to know what function called it and where it should jump to after its done its job - in the end, calling onDone(x) is a bit similar to doing return x. Of course, you could have hardcoded the return function if you wanted.

另外,我在循环函数中添加了一个“onDone”回调,以帮助异步代码看起来更像同步版本。我们的想法是,通过使用返回回调,循环函数不需要知道调用它的函数以及它在完成其工作后应该跳转到的位置 - 最后,调用onDone(x)有点类似于执行返回x。当然,如果你愿意,你可以硬编码返回功能。

function afterAjax(){
    console.log("all done");
}

function loop(){
    if(i >= urls.length){
       afterAjax();
    }
    //...
}

loop();

Finally, coding recursive loops like this is a bit annoying and there are many libraries out there that provide functions to encapsulate these hight level sequentialization and parallelization patterns. In particular, error handling (try-catch) is specially hard to do by hand with callbacks. If you are doing any more non-tricial Async stuff I would highly recommend looking into some of these libraries.

最后,像这样的编码递归循环有点烦人,并且有许多库提供了封装这些高级序列化和并行化模式的函数。特别是,错误处理(try-catch)特别难以通过回调手动完成。如果你正在做任何更多的非特里异步的东西,我强烈建议你看一些这些库。