w3schools una sincronas promises promesas promesa hacer funciones encadenamiento como await anidadas javascript ember.js promise rsvp.js

javascript - una - ¿Cómo puedo ejecutar un conjunto de promesas en orden secuencial?



promise javascript (7)

Camino ES7 en 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>

Esto ejecutará las funciones dadas secuencialmente (una por una), no en paralelo. El parámetro promises es una matriz de funciones que devuelven Promise .

Ejemplo de Plunker con el código anterior: http://plnkr.co/edit/UP0rhD?p=preview

Tengo una serie de promesas que deben ejecutarse en orden secuencial.

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

Llamar a RSVP.all los ejecutará en paralelo:

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

Pero, ¿cómo puedo ejecutarlos en secuencia?

Puedo apilarlos manualmente así

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

pero el problema es que el número de promesas varía y el conjunto de promesas se genera dinámicamente.


Con las funciones asíncronas de ECMAScript 2017 se haría así:

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

Puede usar BabelJS para usar funciones asíncronas ahora


Si ya los tienes en una matriz, entonces ya están ejecutándose. Si tienes una promesa, ya está ejecutándose. Esto no es una preocupación de promesas (IE no son como Task C # en ese aspecto con el método .Start() ). .all no ejecuta nada, solo devuelve una promesa.

Si tiene una serie de funciones de retorno prometedoras:

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

O valores:

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


Todo es necesario para resolver que es un bucle 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); }); }


Tuve un problema similar e hice una función recursiva que ejecuta funciones una a una secuencialmente.

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

En caso de que necesite recopilar resultados de estas funciones:

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([]); };


Un segundo intento de respuesta en el que trato de ser más explicativo:

Primero, algunos antecedentes necesarios, del RSVP README :

La parte realmente asombrosa viene cuando devuelves una promesa del primer controlador ... Esto te permite aplanar las devoluciones de llamada anidadas, y es la característica principal de las promesas que previenen la "deriva hacia la derecha" en programas con una gran cantidad de código asincrónico.

Esta es precisamente la forma en que haces promesas secuencial, devolviendo la promesa posterior desde el then de la promesa que debe terminar antes.

Es útil pensar en un conjunto de promesas tales como un árbol, donde las ramas representan procesos secuenciales, y las hojas representan procesos concurrentes.

El proceso de construcción de este árbol de promesas es análogo a la tarea muy común de construir otros tipos de árboles: mantenga un puntero o referencia al árbol en el que actualmente está agregando ramas y agregue cosas iterativamente.

Como señaló @Esailija en su respuesta, si tiene una serie de funciones de retorno de promesas que no admiten argumentos, puede usar reduce para construir el árbol por usted. Si alguna vez ha implementado Reducir para usted, comprenderá que lo que reduce está detrás de escena en la respuesta de @ Esailija es mantener una referencia a la promesa actual ( cur ) y hacer que cada promesa devuelva la siguiente promesa en ese then .

Si NO tienes una buena matriz de homogéneos (con respecto a los argumentos que toman / devuelven) prometen funciones de retorno, o si necesitas una estructura más complicada que una secuencia lineal simple, puedes construir el árbol de las promesas tú mismo manteniendo una referencia al puesto en el árbol de promesas en el que desea agregar nuevas promesas:

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();

Puede construir combinaciones de procesos simultáneos y secuenciales utilizando RSVP.all para agregar varias "hojas" a una "rama" prometedora. Mi respuesta downvoted-por-ser-demasiado-complicada muestra un ejemplo de eso.

También puede usar Ember.run.scheduleOnce (''afterRender'') para asegurarse de que algo hecho en una promesa se represente antes de que se emita la próxima promesa: mi respuesta downvoted-for-being-too-complicated también muestra un ejemplo de eso.


Voy a dejar esta respuesta aquí porque me habría ayudado cuando vine a buscar una solución a mi problema.

Lo que buscaba era esencialmente mapSeries ... y resulta que estoy mapeando más de un conjunto de valores ... y quiero los resultados ...

Por lo tanto, aquí está todo lo que tengo, FWIW, para ayudar a otros a buscar cosas similares en el futuro ...

(Tenga en cuenta que el contexto es una aplicación de brasas)

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