Javascript 使用承诺迭代同步ajax调用
我目前有一些jQuery代码,看起来有点像这样: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
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"));