我目前有一些看起来有点像这样的jQuery代码:
for ( i = 0; i < limitVar; i++ ) {
doAjaxStuff(i);
}
function doAjaxStuff( i ) {
Here we make a SYNCHRONOUS ajax call, sending i.
}
ajax调用需要是同步的 - 在最后一个调用完成之前不会触发。
由于不推荐使用同步JS,我想将此代码移动到使用promises。我怎么做到这一点?我一直无法找到足够接近这种情况的例子。
答案 0 :(得分:1)
你不能在浏览器中做同步ajax(从技术上讲,你可以在某些情况下,但这样做是一个非常糟糕的主意,因为它在ajax调用期间锁定了浏览器)。
相反,你重新设计你的循环,以便它只在前一个完成时执行下一个ajax调用,这意味着你必须手动循环,你不能使用for
循环。由于您的代码是伪代码(您不显示真正的ajax操作),我将使用jQuery ajax示例,但您可以替换任何ajax函数,只要它返回一个promise或者在完成时使用回调来发出信号。
一般的想法是你为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
});
如果您没有数据数组,但只想要一个循环索引:
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不大并且决定是否继续循环没有其他逻辑,如果你有一个返回一个promise的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
});
如果你没有使用返回promise的ajax函数,那么只需几行代码就可以用你的函数包装你的函数,然后你可以更容易地使用这些设计模式。 / p>
答案 1 :(得分:0)
使用一些单独的函数处理数组。每次从数组中取出另一个元素,然后处理它,完成后再次调用该函数。如果列表中没有其他项目,则整个过程完成。
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 ) { ... }
答案 2 :(得分:-1)
这是一个非常简单的模式:
$$
或者如果您使用数组作为输入:
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"));