Ich habe eine Reihe von Versprechungen, die in sequentieller Reihenfolge ausgeführt werden müssen.
var promises = [promise1, promise2, ..., promiseN];
Wenn Sie RSVP.all aufrufen, werden sie parallel ausgeführt:
RSVP.all(promises).then(...);
Aber wie kann ich sie nacheinander ausführen?
Ich kann sie so manuell stapeln
RSVP.resolve()
.then(promise1)
.then(promise2)
...
.then(promiseN)
.then(...);
Das Problem ist jedoch, dass die Anzahl der Versprechen variiert und die Anzahl der Versprechen dynamisch aufgebaut wird.
javascript
ember.js
promise
rsvp.js
jaaksarv
quelle
quelle
Antworten:
Wenn Sie sie bereits in einem Array haben, werden sie bereits ausgeführt. Wenn Sie ein Versprechen haben, wird es bereits ausgeführt. Dies ist kein Problem von Versprechungen (dh sie sind
Task
in dieser Hinsicht nicht wie C # s mit der.Start()
Methode)..all
führt nichts aus, sondern gibt nur ein Versprechen zurück.Wenn Sie eine Reihe von Funktionen zur Rückgabe von Versprechen haben:
var tasks = [fn1, fn2, fn3...]; tasks.reduce(function(cur, next) { return cur.then(next); }, RSVP.resolve()).then(function() { //all executed });
Oder Werte:
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 });
quelle
.then
, in diesem Beispiel wird sie einfach ignoriert ...Mit asynchronen Funktionen von ECMAScript 2017 würde dies folgendermaßen geschehen:
async function executeSequentially() { const tasks = [fn1, fn2, fn3] for (const fn of tasks) { await fn() } }
Mit BabelJS können Sie jetzt asynchrone Funktionen verwenden
quelle
fn1, fn2, fn3
hier Funktionen sind, z. B.() => yourFunctionReturningAPromise()
im Gegensatz zu nuryourFunctionReturningAPromise()
. Dies ist auch der Grund, warumawait fn()
stattdessen nur notwendig istawait fn
. Weitere Informationen finden Sie in den offiziellen Dokumenten . Entschuldigung für das Posten als Kommentar, aber die Bearbeitungswarteschlange ist voll :)ES7 Weg im Jahr 2017.
<script> var funcs = [ _ => new Promise(resolve => setTimeout(_ => resolve("1"), 1000)), _ => new Promise(resolve => setTimeout(_ => resolve("2"), 1000)), _ => new Promise(resolve => setTimeout(_ => resolve("3"), 1000)), _ => new Promise(resolve => setTimeout(_ => resolve("4"), 1000)), _ => new Promise(resolve => setTimeout(_ => resolve("5"), 1000)), _ => new Promise(resolve => setTimeout(_ => resolve("6"), 1000)), _ => new Promise(resolve => setTimeout(_ => resolve("7"), 1000)) ]; async function runPromisesInSequence(promises) { for (let promise of promises) { console.log(await promise()); } } </script> <button onClick="runPromisesInSequence(funcs)">Do the thing</button>
Dadurch werden die angegebenen Funktionen nacheinander (einzeln) und nicht parallel ausgeführt. Der Parameter
promises
ist ein Array von Funktionen, die zurückgebenPromise
.Plunker-Beispiel mit dem obigen Code: http://plnkr.co/edit/UP0rhD?p=preview
quelle
Ein zweiter Versuch einer Antwort, in der ich versuche, erklärender zu sein:
Zunächst einige erforderliche Hintergrundinformationen aus der RSVP-README :
Genau so machen Sie Versprechen nacheinander, indem Sie das spätere Versprechen von
then
dem Versprechen zurückgeben, das davor enden sollte.Es ist hilfreich, sich eine solche Reihe von Versprechungen als einen Baum vorzustellen, in dem die Zweige sequentielle Prozesse und die Blätter gleichzeitige Prozesse darstellen.
Der Prozess des Aufbaus eines solchen Baums von Versprechungen ist analog zu der sehr häufigen Aufgabe, andere Arten von Bäumen zu bauen: Behalten Sie einen Zeiger oder Verweis darauf bei, wo in dem Baum Sie gerade Zweige hinzufügen, und fügen Sie iterativ Dinge hinzu.
Wie @Esailija in seiner Antwort betonte, können Sie
reduce
den Baum ordentlich erstellen , wenn Sie über eine Reihe von Funktionen verfügen, die Versprechen zurückgeben und keine Argumente enthalten . Wenn Sie Reduce jemals für sich selbst implementiert haben, werden Sie verstehen, dass Reduce hinter den Kulissen in @ Esailijas Antwort darin besteht, einen Verweis auf das aktuelle Versprechen (cur
) beizubehalten und jedes Versprechen das nächste Versprechen in seinem zurückgeben zu lassenthen
.Wenn Sie KEINE schöne Reihe homogener (in Bezug auf die Argumente, die sie annehmen / zurückgeben) Versprechen zurückgebender Funktionen haben oder wenn Sie eine kompliziertere Struktur als eine einfache lineare Sequenz benötigen, können Sie den Baum der Versprechen selbst erstellen, indem Sie ihn beibehalten Ein Verweis auf die Position im Versprechungsbaum, an der Sie neue Versprechungen hinzufügen möchten:
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();
Sie können Kombinationen von gleichzeitigen und sequentiellen Prozessen erstellen, indem Sie RSVP.all verwenden, um einem versprochenen "Zweig" mehrere "Blätter" hinzuzufügen. Meine Antwort, die als zu kompliziert eingestuft wurde, zeigt ein Beispiel dafür.
Sie können auch Ember.run.scheduleOnce ('afterRender') verwenden, um sicherzustellen, dass etwas, das in einem Versprechen getan wurde, gerendert wird, bevor das nächste Versprechen ausgelöst wird. Meine Antwort, die als zu kompliziert eingestuft wurde, zeigt auch ein Beispiel dafür.
quelle
then
gewünscht ist. Sie haben viele zusätzliche Informationen angegeben, die die Antwort auf die gestellte Frage verbergen.Promise.resolve().then(...).then(...)...
, nicht dass das Array wuchs, während die Versprechen ausgeführt wurden. Natürlich ist jetzt alles umstritten.Ein weiterer Ansatz besteht darin, eine globale Sequenzfunktion für den
Promise
Prototyp zu definieren .Promise.prototype.sequence = async (promiseFns) => { for (let promiseFn of promiseFns) { await promiseFn(); } }
Dann können Sie es überall verwenden, genau wie
Promise.all()
Beispiel
const timeout = async ms => new Promise(resolve => setTimeout(() => { console.log("done", ms); resolve(); }, ms) ); // Executed one after the other await Promise.sequence([() => timeout(1000), () => timeout(500)]); // done: 1000 // done: 500 // Executed in parallel await Promise.all([timeout(1000), timeout(500)]); // done: 500 // done: 1000
Haftungsausschluss: Bearbeiten Sie Prototypen sorgfältig!
quelle
Alles was benötigt wird um das zu lösen ist eine
for
Schleife :)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); }); }
quelle
if(!chain) chain = promises[i]();
ein()
am Ende? Ich denke, in dem Fall, in dem die Kette leer ist (Iteration 0), möchte man nur das rohe Versprechen haben, und dann kann die Schleife jedes nachfolgende Versprechen in das der Kette einfügen.then()
. Wäre das nichtif(!chain) chain = promises[i];
? Vielleicht habe ich hier etwas nicht verstanden.a,b,c
sind in der Tat Funktionen, die Versprechen zurückgeben, und keine Versprechen. Das Obige macht also Sinn. Aber welchen Nutzen hat es, die Versprechen auf diese Weise zu verpacken?Ich hatte ein ähnliches Problem und habe eine rekursive Funktion erstellt, die Funktionen nacheinander nacheinander ausführt.
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(); };
Falls Sie die Ausgabe dieser Funktionen erfassen müssen:
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([]); };
quelle
export type PromiseFn = () => Promise<any>; export class PromiseSequence { private fns: PromiseFn[] = []; push(fn: PromiseFn) { this.fns.push(fn) } async run() { for (const fn of this.fns) { await fn(); } } }
dann
const seq = new PromiseSequence(); seq.push(() => Promise.resolve(1)); seq.push(() => Promise.resolve(2)); seq.run();
Es ist auch möglich, die zurückgegebenen Versprechen in einer anderen privaten Variable zu speichern und an Rückrufe weiterzugeben
quelle
Das, wonach ich gesucht habe, war im Wesentlichen mapSeries, und ich bin dabei, das Speichern über eine Reihe von Werten abzubilden, und ich möchte die Ergebnisse.
Also, so weit ich gekommen bin, um anderen zu helfen, in Zukunft nach ähnlichen Dingen zu suchen.
(Beachten Sie, dass der Kontext eine Ember-App ist).
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); } });
quelle