简体   繁体   English

JavaScript:同步执行一系列承诺

[英]JavaScript: Perform a chain of promises synchronously

I have a request promises that I need to perform over a loop, something like: 我有一个请求承诺,我需要执行一个循环,如:

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

The problem is I never know how many elements will be in the array, so I would need a dynamic pattern. 问题是我永远不知道数组中有多少元素,所以我需要一个动态模式。 Is it possible to mix the sync and async worlds, so that only one request is active at a moment (sequence being not important)? 是否可以混合同步和异步世界,以便一时只有一个请求处于活动状态(序列不重要)?

A classic way to iterate over an array sequentually, calling some async operation on each array element is by using .reduce() and chaining to an initial promise as shown below: 迭代迭代数组的经典方法是,在每个数组元素上调用一些异步操作是使用.reduce()并链接到初始的promise,如下所示:

The problem is I never know how many elements will be in the array, so I would need a dynamic pattern. 问题是我永远不知道数组中有多少元素,所以我需要一个动态模式。

You can use chaining of promises to sequence them one after. 您可以使用promises链接对其进行排序。 For this, it is useful to use .reduce() to iterate the array since it offers the right type of iteration that keeps track of an accumulated value (a promise in this case) as one iterates the array. 为此,使用.reduce()迭代数组是很有用的,因为它提供了正确的迭代类型,当迭代数组时,它会跟踪累积值(在这种情况下是一个promise)。 You could make almost any array iteration scheme work using extra variables, this just lines up well with .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
});

This passes a resolved promise to ids.reduce() as the head of the promise chain. 这会将已解决的承诺传递给ids.reduce()作为承诺链的负责人。 Then, it does a .then() on that promise and returns a new promise for each item in the array (via the .reduce() callback). 然后,它在该promise上执行.then()并为数组中的每个项返回一个新的promise(通过.reduce()回调)。 The final result of the .reduce() call will be a promise which, when resolved means the entire chain is done. .reduce()调用的最终结果将是一个承诺,当解析时意味着整个链完成。

The key to understanding this is to remember that p.then() returns a new promise so we just keep calling .then() on each new promise and we return the promise from each operation in each .then() handler. 理解这一点的关键是要记住p.then()返回一个新的promise,所以我们只是在每个新的promise上调用.then() ,并从每个.then()处理程序中的每个操作返回promise。 This has the effect of chaining all the promises together into one sequential chain. 这具有将所有承诺链接在一起成为一个顺序链的效果。

Is it possible to mix the sync and async worlds, so that only one request is active at a moment (sequence being not important)? 是否可以混合同步和异步世界,以便一时只有一个请求处于活动状态(序列不重要)?

I'm not sure what you mean by "mix the sync and async worlds". 我不确定你的意思是“混合同步和异步世界”。 The way to make sure that only one request is ever in-flight at a time is to sequence them to be one after the other so the next one starts only when the prior one finishes. 确保一次只有一个请求在飞行中的方法是将它们一个接一个地排序,以便下一个请求仅在前一个请求完成时开始。 This also happens to guarantee the execution order even though you say that isn't important in this case, but it is a by-product of making sure only one is in-flight at a time. 这也恰好保证了执行顺序,即使你说在这种情况下并不重要,但它是确保一次只有一个在飞行中的副产品。

And, here's a working snippet: 而且,这是一个工作片段:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM