JavaScript:同步执行一系列承诺

JavaScript: Perform a chain of promises synchronously

本文关键字:一系列 承诺 执行 同步 JavaScript      更新时间:2023-09-26

我有一个需要在循环中执行的请求承诺,类似于:

var ids = [1,2,3];
doPromise(1).then(function(){
  doPromise(2).then(function(){
    doPromise(3);
  }
})

问题是我永远不知道数组中有多少元素,所以我需要一个动态模式。是否可以将同步和异步世界混合在一起,以便一次只有一个请求处于活动状态(序列并不重要)?

顺序迭代数组,在每个数组元素上调用一些异步操作的经典方法是使用.reduce()并链接到初始promise,如下所示:

问题是我永远不知道数组中会有多少元素,所以我需要一个动态的模式。

您可以使用承诺的链接将它们依次排列。为此,使用.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传递给作为promise链头的ids.reduce()。然后,它对该promise执行.then(),并为数组中的每个项返回一个新的promise(通过.reduce()回调)。.reduce()调用的最终结果将是一个promise,当它被解析时,意味着整个链都完成了。

理解这一点的关键是要记住,p.then()返回一个新的promise,所以我们只需要在每个新的promise上继续调用.then(),然后从每个.then()处理程序中的每个操作返回promise。这具有将所有承诺链接到一个顺序链中的效果。

是否可以将同步和异步世界混合在一起,以便只有一个请求在某个时刻处于活动状态(序列不重要)?

我不知道你说的"混合同步和异步世界"是什么意思。确保一次只有一个请求在运行的方法是将它们依次排列,这样下一个请求只有在前一个请求完成时才开始。这也恰好保证了执行顺序,尽管你说在这种情况下这并不重要,但这是确保一次只有一个执行顺序的副产品。

这里有一个工作片段:

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");
});