依次迭代数组的经典方法是,对每个数组元素调用一些异步操作,方法是使用.reduce() 并链接到如下所示的初始承诺:
问题是我永远不知道数组中有多少元素,所以
我需要一个动态模式。
您可以使用一系列承诺来对它们进行排序。为此,使用.reduce() 迭代数组很有用,因为它提供了正确的迭代类型,可以在迭代数组时跟踪累积值(在这种情况下是一个承诺)。您可以使用额外的变量使几乎任何数组迭代方案都工作,这与.reduce() 非常吻合:
var ids = [1,2,3,4,5,6,7];
ids.reduce(function(p, item) {
return p.then(function() {
return doPromise(item);
});
}, Promise.resolve()).then(function(results) {
// all done here with array of results
});
这会将一个已解决的 Promise 传递给 ids.reduce() 作为 Promise 链的头部。然后,它对该承诺执行.then() 并为数组中的每个项目返回一个新承诺(通过.reduce() 回调)。 .reduce() 调用的最终结果将是一个承诺,当它被解决时意味着整个链已经完成。
理解这一点的关键是要记住 p.then() 返回一个新的 Promise,因此我们只需在每个新 Promise 上继续调用 .then() 并从每个 .then() 处理程序中的每个操作返回 Promise。这具有将所有 Promise 链接到一个顺序链中的效果。
是否可以混合同步和异步世界,这样只有一个
请求在某个时刻处于活动状态(顺序不重要)?
我不确定您所说的“混合同步和异步世界”是什么意思。确保一次只有一个请求在进行中的方法是将它们排序为一个接一个,这样下一个请求只有在前一个请求完成时才开始。这也恰好保证了执行顺序,即使您说在这种情况下这并不重要,但它是确保一次只有一个在运行中的副产品。
还有,这是一个有效的 sn-p:
function log(msg) {
var d = document.createElement("div");
d.textContent = msg;
document.body.appendChild(d);
}
function doPromise(x) {
return new Promise(function(resolve) {
setTimeout(function() {
log(x);
resolve(x);
}, Math.floor(Math.random() * 1000));
});
}
var ids = [1,2,3,4,5,6,7];
ids.reduce(function(p, item) {
return p.then(function() {
return doPromise(item);
});
}, Promise.resolve()).then(function() {
// all done here
log("all done");
});