我怎样才能按顺序执行promise的数组?

我有一系列的承诺,需要按顺序运行。

var promises = [promise1, promise2, ..., promiseN]; 

调用RSVP.all将并行执行它们:

 RSVP.all(promises).then(...); 

但是,我怎样才能顺序运行它们?

我可以像这样手动堆叠它们

 RSVP.resolve() .then(promise1) .then(promise2) ... .then(promiseN) .then(...); 

但是问题是promise的数量是不一样的,promise的数组是dynamic的。

如果你已经有一个数组,那么他们已经在执行。 如果你有承诺,那么它已经在执行了。 这不是承诺的关注(IE浏览器它们不像C# Task在这方面用.Start()方法)。 .all不执行任何事情只是返回一个承诺。

如果你有一个promise返回函数的数组:

 var tasks = [fn1, fn2, fn3...]; tasks.reduce(function(cur, next) { return cur.then(next); }, RSVP.resolve()).then(function() { //all executed }); 

或值:

 var idsToDelete = [1,2,3]; idsToDelete.reduce(function(cur, next) { return cur.then(function() { return http.post("/delete.php?id=" + next); }); }, RSVP.resolve()).then(function() { //all executed }); 

使用ECMAScript 2017asynchronous函数,可以这样做:

 async function executeSequentially() { const tasks = [fn1, fn2, fn3] for (const fn of tasks) { await fn() } } 

您现在可以使用BabelJS来使用asynchronousfunction

第二次尝试的答案,我试图更加解释:

首先,一些必要的背景,从RSVP自述 :

当你从第一个处理程序返回一个承诺时,真的很棒的部分来了…这可以让你平滑嵌套的callback,并且是承诺的主要function,可以防止有很多asynchronous代码的程序“向右漂移”。

这正是你如何做出连续的承诺,通过then应承诺的承诺返回。

将这样一组承诺看作一棵树,其中分支表示顺序进程,叶子表示并发进程是有帮助的。

build立这样一个承诺树的过程类似于构build其他types的树的常见任务:维护一个指针或引用到树中您正在添加分支的位置,并迭代地添加事物。

正如@Esailija在他的回答中指出的那样,如果你有一个不带参数的promise返回函数的数组,你可以使用reduce来整齐地为你构build树。 如果你曾经为自己实施过减免,那么你会明白,@ Esailija的回答在幕后做了什么,是保持对当前承诺( cur )的引用,并且每个承诺都会在then答应下一个承诺。

如果你没有一个很好的齐次数组(相对于他们所接受/返回的参数)承诺返回函数,或者如果你需要一个比简单的线性序列更复杂的结构,你可以通过维护来构build承诺树对您希望添加新承诺的承诺树中的位置的引用:

 var root_promise = current_promise = Ember.Deferred.create(); // you can also just use your first real promise as the root; the advantage of // using an empty one is in the case where the process of BUILDING your tree of // promises is also asynchronous and you need to make sure it is built first // before starting it current_promise = current_promise.then(function(){ return // ...something that returns a promise...; }); current_promise = current_promise.then(function(){ return // ...something that returns a promise...; }); // etc. root_promise.resolve(); 

您可以通过使用RSVP.all来为承诺“分支”添加多个“树叶”来构build并发和顺序进程的组合。 我低调的存在 – 太复杂的答案就是一个例子。

您也可以使用Ember.run.scheduleOnce('afterRender')来确保在下一个承诺被触发之前,在一个承诺中完成的事情得到了呈现 – 我的低估为过于复杂的答案也显示了一个例子。

我将在这里留下这个答案,因为当我来到这里寻求解决我的问题时,这将帮助我。

我后来的事情本质上是mapSeries …我正好映射保存在一组值…我想要的结果…

所以,就我所知,FWIW帮助其他人在未来寻找类似的东西。

(请注意,上下文是一个烬应用程序)

 App = Ember.Application.create(); App.Router.map(function () { // put your routes here }); App.IndexRoute = Ember.Route.extend({ model: function () { var block1 = Em.Object.create({save: function() { return Em.RSVP.resolve("hello"); }}); var block2 = Em.Object.create({save: function() { return Em.RSVP.resolve("this"); }}); var block3 = Em.Object.create({save: function() { return Em.RSVP.resolve("is in sequence"); }}); var values = [block1, block2, block3]; // want to sequentially iterate over each, use reduce, build an array of results similarly to map... var x = values.reduce(function(memo, current) { var last; if(memo.length < 1) { last = current.save(); } else { last = memo[memo.length - 1]; } return memo.concat(last.then(function(results) { return current.save(); })); }, []); return Ember.RSVP.all(x); } }); 

所有需要解决的是for循环:)

 var promises = [a,b,c]; var chain; for(let i in promises){ if(chain) chain = chain.then(promises[i]); if(!chain) chain = promises[i](); } function a(){ return new Promise((resolve)=>{ setTimeout(function(){ console.log('resolve A'); resolve(); },1000); }); } function b(){ return new Promise((resolve)=>{ setTimeout(function(){ console.log('resolve B'); resolve(); },500); }); } function c(){ return new Promise((resolve)=>{ setTimeout(function(){ console.log('resolve C'); resolve(); },100); }); } 

我有类似的问题,我做了一个顺序运行function的recursionfunction。

 var tasks = [fn1, fn2, fn3]; var executeSequentially = function(tasks) { if (tasks && tasks.length > 0) { var task = tasks.shift(); return task().then(function() { return executeSequentially(tasks); }); } return Promise.resolve(); }; 

如果您需要收集这些function的输出:

 var tasks = [fn1, fn2, fn3]; var executeSequentially = function(tasks) { if (tasks && tasks.length > 0) { var task = tasks.shift(); return task().then(function(output) { return executeSequentially(tasks).then(function(outputs) { outputs.push(output); return Promise.resolve(outputs); }); }); } return Promise.resolve([]); }; 

ES7在2017年的方式。

  <script> var funcs = [ _ => new Promise(res => setTimeout(_ => res("1"), 1000)), _ => new Promise(res => setTimeout(_ => res("2"), 1000)), _ => new Promise(res => setTimeout(_ => res("3"), 1000)), _ => new Promise(res => setTimeout(_ => res("4"), 1000)), _ => new Promise(res => setTimeout(_ => res("5"), 1000)), _ => new Promise(res => setTimeout(_ => res("6"), 1000)), _ => new Promise(res => setTimeout(_ => res("7"), 1000)) ]; async function runPromisesInSequence(promises) { for (let promise of promises) { console.log(await promise()); } } </script> <button onClick="runPromisesInSequence(funcs)">Do the thing</button> 

这将按顺序(逐个)执行给定的function,而不是并行执行。 参数promises是一个返回Promise的函数数组。

与上面的代码Plunker示例: http ://plnkr.co/edit/UP0rhD?p=preview