Javascript 使用承诺迭代同步ajax调用

Javascript 使用承诺迭代同步ajax调用,javascript,jquery,ajax,promise,synchronous,Javascript,Jquery,Ajax,Promise,Synchronous,我目前有一些jQuery代码,看起来有点像这样: for ( i = 0; i < limitVar; i++ ) { doAjaxStuff(i); } function doAjaxStuff( i ) { Here we make a SYNCHRONOUS ajax call, sending i. } (i=0;i

我目前有一些jQuery代码,看起来有点像这样:

for ( i = 0; i < limitVar; i++ ) {
doAjaxStuff(i);
}

function doAjaxStuff( i ) {
Here we make a SYNCHRONOUS ajax call, sending i.
}
(i=0;i{ DOA(一); } 功能性材料(一){ 这里我们进行一个同步ajax调用,发送i。 } ajax调用需要是同步的,直到最后一个调用完成后才会触发


由于synchronous JS已被弃用,我希望将此代码移动到使用Promissions。我将如何实现这一点?我找不到一个足够适合这种情况的例子。

使用一些单独的函数处理数组。每次从数组中取出另一个元素,然后处理它,完成后再次调用该函数。如果列表中没有其他项目,则整个过程完成

var listOfRequests = ...; new Promise( function( resolve, reject ) { requestNext(); function requestNext() { if ( !listOfRequests.length ) { return resolve(); } var next = listOfRequests.shift(); doAjaxStuff( next, reject, requestNext ); } } ) doAjaxStuff( request, errCallback, doneCallback ) { ... } var listOfRequests=。。。; 新承诺(功能(解决、拒绝){ requestNext(); 函数requestNext(){ 如果(!listOfRequests.length){ 返回resolve(); } var next=listOfRequests.shift(); doAjaxStuff(next、reject、requestNext); } } ) doAjaxStuff(请求、errCallback、doneCallback){ ... }
您不在浏览器中执行同步ajax(从技术上讲,在某些情况下您可以这样做,但这样做是一个非常糟糕的主意,因为它会在ajax调用期间锁定浏览器)

相反,您需要重新设计循环,以便在上一个ajax调用完成时,它只执行下一个ajax调用,这意味着您必须手动循环,而不能使用
for
循环。由于您的代码是伪代码(您没有显示真正的ajax操作),因此我将使用jQuery ajax示例,但您可以替换任何ajax函数,只要它返回承诺或在完成时使用回调来发出信号

一般的想法是为ajax调用创建一个函数,然后使用该函数的完成回调来增加索引,然后运行循环的下一次迭代

function runLoop(data) {
    var i = 0;

    function next() {
        if (i < data.length) {
            return $.ajax(data[i]).then(function(data) {
                ++i;
                return next();
            });
         else {
             // all done with loop
         }
    }
    return next();
}

// call it like this
runLoop(someArray).then(function() {
   // all done here
});
函数运行循环(数据){
var i=0;
函数next(){
if(i<数据长度){
返回$.ajax(数据[i]),然后返回(函数(数据){
++一,;
返回next();
});
否则{
//全部用循环完成
}
}
返回next();
}
//这样说吧
runLoop(someArray).then(function(){
//全部在这里完成
});
如果没有数据数组,但只需要循环索引:

function runLoop(limitVar) {
    var i = 0;

    function next() {
        if (i < limitVar) {
            return $.ajax(something_with_i_in_it).then(function(data) {
                ++i;
                return next();
            });
         else {
             // all done with loop
         }
    }
    return next();
}

// call it like this
runLoop(theLimit).then(function() {
   // all done here
});
函数运行循环(limitVar){
var i=0;
函数next(){
if(i
如果您的limitVar不大,并且在决定是否继续循环时没有涉及其他逻辑,那么如果您有一个返回承诺的ajax函数,也可以使用稍微简单一点的模式:

function runLoop(limitVar) {
    var p = Promise.resolve();
    for (var i = 0; i < limitVar; i++) {
        p = p.then(function(prevResult) {
            return someAjax(i);
        });
    }
    return p;
}

// call it like this
runLoop(theLimit).then(function() {
   // all done here
});
函数运行循环(limitVar){
var p=Promise.resolve();
对于(var i=0;i

如果您没有使用返回承诺的ajax函数,那么只需几行代码就可以将函数包装为返回承诺的函数,这样您就可以更轻松地使用这些设计模式。

这是一个非常简单的模式:

var queue = Promise.resolve();
var nop = () => null;

for(let i=0; i<limitVar; ++i){
  queue = queue.then(() => doAjaxStuff(i));
  //or if you want to ignore Errors
  //queue = queue.then(() => doAjaxStuff(i)).catch(nop);
}

queue.then(() => console.log("finished"));

@KevinB Promise.all()一次触发所有请求。若数组足够大,那个么肯定会耗尽资源,导致请求失败。您可以使用[].reduce创建一个链,一个接一个地调用它们。例如:移动到承诺意味着移动到异步。为什么要否决?这个答案有什么错?如果您提供有关否决原因的反馈,人们只能改进他们的答案以解决否决反对意见。
var done = data.reduce(
    (queue, value, index) => queue.then(() => doSomethingWith(value, index)), 
    Promise.resolve()
  );

done.then(() => console.log("finished"));