我想在循环中运行一些异步任务,但它应该按顺序执行(一个接一个)。它应该是vanilla JS,而不是任何库。
var doSome = function(i) {
return Promise.resolve(setTimeout(() => {
console.log('done... ' + i)
}, 1000 * (i%3)));
}
var looper = function() {
var p = Promise.resolve();
[1,2,3].forEach((n) => {
p = p.then(() => doSome(n))
})
return p;
}
looper();
当前输出:
calling for ...1
calling for ...2
calling for ...3
Promise {<resolved>: 8260}
done... 3
done... 1
done... 2
预期输出:
calling for ...1
calling for ...2
calling for ...3
Promise {<resolved>: 8260}
done... 1
done... 2
done... 3
注意:请回答,如果您尝试过并且按预期工作
答案 0 :(得分:3)
因此,从下面的评论中,我认为您自己的示例代码与您的描述并不完全匹配。我认为你想要的例子更接近下面的片段:
var doSome = function(i) {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(`Completing ${i}`), 1000*(i%3))
});
}
var looper = function() {
[1,2,3].forEach((n) => {
doSome(n).then(console.log);
});
}
looper();
&#13;
这里,迭代数组[1, 2, 3]
,并为每个数组生成异步过程。当每个异步过程完成时,我们.then
对它们和控制台记录它们的解析结果。
那么,现在问题是如何最好地排队结果?下面,我将它们存储到一个数组中,然后利用async
/ await
来暂停执行结果,直到它们按顺序完成。
// This is probably what you want
var doSome = function(i) {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(`Completing ${i}`), 1000*(i%3))
});
}
var looper = async function() {
const nums = [1,2,3];
const promises = []
nums.forEach((n) => {
console.log(`Queueing ${n}`);
promises.push(doSome(n));
});
for (let promise of promises) {
const result = await promise;
console.log(result);
}
}
looper();
&#13;
现在,我们可以消除了一个循环,并且只在最后一次完成后执行了一个循环:
// Don't use this-- it is less efficient
var doSome = function(i) {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(`Completing ${i}`), 1000*(i%3))
});
}
var looper = async function() {
const nums = [1,2,3];
const promises = [];
for (let n of nums) {
console.log(`Queueing ${n}`);
const result = await doSome(n);
console.log(result);
};
}
looper();
&#13;
但是,正如您在日志中看到的那样,这种方法不会排队下一个异步进程,直到前一个异步进程完成为止。这是不可取的,并不符合您的使用案例。我们从这个前面的双循环方法得到的是,所有异步进程都会立即执行,但之后我们对结果进行排序/排队,以便它们遵循我们预定义的顺序,而不是它们解决的顺序。
关于Promise.all
,async
/ await
以及排队的预期行为:
因此,如果您想避免使用async
/ await
,我认为您可以编写某种实用程序:
var doSome = function(i) {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(`Completing ${i}`), 1000*(i%3))
});
}
function handlePromiseQueue(queue) {
let promise = queue.shift();
promise.then((data) => {
console.log(data)
if (queue.length > 0) {
handlePromiseQueue(queue);
}
})
}
var looper = function() {
const nums = [1,2,3];
const promises = []
nums.forEach((n) => {
console.log(`Queueing ${n}`);
promises.push(doSome(n));
});
handlePromiseQueue(promises);
}
looper();
&#13;
HOWEVER ,让我说清楚 - 如果用户Bergi的断言是正确的,并且每个异步承诺不重要一旦它解决就被执行,只有在他们所有都回来之后才会被执行,然后可以用Promise.all
100%简化:
// This is probably what you want
var doSome = function(i) {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(`Completing ${i}`), 1000*(i%3))
});
}
function handlePromiseQueue(queue) {
let promise = queue.shift();
promise.then((data) => {
console.log(data)
if (queue.length > 0) {
handlePromiseQueue(queue);
}
})
}
var looper = function() {
const nums = [1,2,3];
const promises = []
nums.forEach((n) => {
console.log(`Queueing ${n}`);
promises.push(doSome(n));
});
Promise.all(promises).then(() => handlePromiseQueue(promises));
}
looper();
&#13;
最后,正如Bergi所指出的那样,我没有在这些不同的承诺上设置任何catch
,而是在这里玩得很快 - 我为了简洁起见省略了它们,但为了你的目的,你会想要包括正确处理错误或错误请求。