w3schools sincronas promises promesas nodejs funciones from ejemplo await async javascript node.js promise es6-promise

javascript - sincronas - ¿Node.js es nativo de Promise.all procesándose en paralelo o secuencialmente?



promises javascript w3schools (10)

Me gustaría aclarar este punto, ya que la documentation no es muy clara al respecto;

P1: ¿ Promise.all(iterable) procesa todas las promesas secuencialmente o en paralelo? O, más específicamente, ¿es el equivalente a ejecutar promesas encadenadas como

p1.then(p2).then(p3).then(p4).then(p5)....

¿o es algún otro tipo de algoritmo en el que todos los p1 , p2 , p3 , p4 , p5 , etc. se p5 al mismo tiempo (en paralelo) y los resultados se devuelven tan pronto como todos se resuelven (o uno rechaza)?

P2: Si Promise.all ejecuta en paralelo, ¿hay alguna forma conveniente de ejecutar una secuencia iterable?

Nota : No quiero usar Q o Bluebird, sino todas las especificaciones nativas de ES6.


¿ Promise.all(iterable) ejecutando todas las promesas?

No, las promesas no pueden "ejecutarse". Comienzan su tarea cuando se están creando , solo representan los resultados, y usted está ejecutando todo en paralelo incluso antes de pasarlos a Promise.all .

Promise.all solo espera múltiples promesas. No le importa en qué orden resuelven, o si los cálculos se ejecutan en paralelo.

¿Hay alguna manera conveniente de ejecutar una secuencia iterable?

Si ya tiene sus promesas, no puede hacer mucho más que Promise.all([p1, p2, p3, …]) (que no tiene una noción de secuencia). Pero si tiene un iterable de funciones asincrónicas, puede ejecutarlas secuencialmente. Básicamente necesitas ir de

[fn1, fn2, fn3, …]

a

fn1().then(fn2).then(fn3).then(…)

y la solución para hacerlo es usar Array::reduce :

iterable.reduce((p, fn) => p.then(fn), Promise.resolve())


En paralelo

await Promise.all(items.map(async item => { await fetchItem(item) }))

Ventajas: más rápido. Todas las iteraciones se ejecutarán incluso si una falla.

En secuencia

for (let i = 0; i < items.length; i++) { await fetchItem(items[i]) }

Ventajas: las variables en el bucle pueden ser compartidas por cada iteración. Se comporta como un código síncrono imperativo normal.


El uso de async espera una serie de promesas que se pueden ejecutar fácilmente de forma secuencial:

let a = [promise1, promise2, promise3]; async function func() { for(let i=0; i<a.length; i++){ await a[i](); } } func();

Nota: en la implementación anterior, si se rechaza una promesa, el resto no se ejecutará. Si desea que se ejecuten todas sus promesas, envuelva su await a[i](); dentro try catch


Esto podría responder parte de su pregunta.

sí, puede encadenar una serie de funciones prometedoras de la siguiente manera ... (esto pasa el resultado de cada función a la siguiente). por supuesto, podría editarlo para pasar el mismo argumento (o ningún argumento) a cada función.

function tester1(a) { return new Promise(function(done) { setTimeout(function() { done(a + 1); }, 1000); }) } function tester2(a) { return new Promise(function(done) { setTimeout(function() { done(a * 5); }, 1000); }) } function promise_chain(args, list, results) { return new Promise(function(done, errs) { var fn = list.shift(); if (results === undefined) results = []; if (typeof fn === ''function'') { fn(args).then(function(result) { results.push(result); console.log(result); promise_chain(result, list, results).then(done); }, errs); } else { done(results); } }); } promise_chain(0, [tester1, tester2, tester1, tester2, tester2]).then(console.log.bind(console), console.error.bind(console));


He estado usando para para resolver promesas secuenciales. No estoy seguro de si ayuda aquí, pero esto es lo que he estado haciendo.

async function run() { for (let val of arr) { const res = await someQuery(val) console.log(val) } } run().then().catch()


La respuesta de Bergi me ayudó a hacer que la llamada fuera síncrona. He agregado un ejemplo a continuación donde llamamos a cada función después de que se llama a la función anterior.

function func1 (param1) { console.log("function1 : " + param1); } function func2 () { console.log("function2"); } function func3 (param2, param3) { console.log("function3 : " + param2 + ", " + param3); } function func4 (param4) { console.log("function4 : " + param4); } param4 = "Kate"; //adding 3 functions to array a=[ ()=>func1("Hi"), ()=>func2(), ()=>func3("Lindsay",param4) ]; //adding 4th function a.push(()=>func4("dad")); //below does func1().then(func2).then(func3).then(func4) a.reduce((p, fn) => p.then(fn), Promise.resolve());


La respuesta de Bergis me puso en el camino correcto usando Array.reduce.

Sin embargo, para que las funciones devuelvan mis promesas de ejecutarse una tras otra, tuve que agregar un poco más de anidamiento.

Mi caso de uso real es una matriz de archivos que necesito transferir en orden uno tras otro debido a los límites posteriores ...

Aquí es con lo que terminé.

getAllFiles().then( (files) => { return files.reduce((p, theFile) => { return p.then(() => { return transferFile(theFile); //function returns a promise }); }, Promise.resolve()).then(()=>{ console.log("All files transferred"); }); }).catch((error)=>{ console.log(error); });

Como sugieren las respuestas anteriores, usando:

getAllFiles().then( (files) => { return files.reduce((p, theFile) => { return p.then(transferFile(theFile)); }, Promise.resolve()).then(()=>{ console.log("All files transferred"); }); }).catch((error)=>{ console.log(error); });

no esperó a que se completara la transferencia antes de comenzar otra y también el texto "Todos los archivos transferidos" llegó incluso antes de que se iniciara la primera transferencia de archivos.

No estoy seguro de lo que hice mal, pero quería compartir lo que funcionó para mí.

Editar: desde que escribí esta publicación, ahora entiendo por qué la primera versión no funcionó. then () espera que una función devuelva una promesa. Por lo tanto, debe pasar el nombre de la función sin paréntesis. Ahora, mi función quiere un argumento, ¡así que necesito envolverme en una función anónima sin tomar ningún argumento!


Puedes hacerlo por bucle.

promesa de devolución de función asíncrona

async function createClient(client) { return await Client.create(client); } let clients = [client1, client2, client3];

si escribe el siguiente código, el cliente se crea paralelamente

const createdClientsArray = yield Promise.all(clients.map((client) => createClient(client); ));

entonces todos los clientes se crean paralelamente. pero si desea crear un cliente secuencialmente, debe usar for loop

const createdClientsArray = []; for(let i = 0; i < clients.length; i++) { const createdClient = yield createClient(clients[i]); createdClientsArray.push(createdClient); }

entonces todos los clientes se crean secuencialmente.

feliz codificación :)


También puede procesar un iterable secuencialmente con una función asíncrona utilizando una función recursiva. Por ejemplo, dada una matriz a para procesar con función asincrónica someAsyncFunction() :

var a = [1, 2, 3, 4, 5, 6] function someAsyncFunction(n) { return new Promise((resolve, reject) => { setTimeout(() => { console.log("someAsyncFunction: ", n) resolve(n) }, Math.random() * 1500) }) } //You can run each array sequentially with: function sequential(arr, index = 0) { if (index >= arr.length) return Promise.resolve() return someAsyncFunction(arr[index]) .then(r => { console.log("got value: ", r) return sequential(arr, index + 1) }) } sequential(a).then(() => console.log("done"))


solo para explicar la respuesta de @ Bergi (que es muy sucinta, pero difícil de entender;)

Este código ejecutará cada elemento de la matriz y agregará la siguiente ''cadena'' al final;

function eachorder(prev,order) { return prev.then(function() { return get_order(order) .then(check_order) .then(update_order); }); } orderArray.reduce(eachorder,Promise.resolve());

Espero que tenga sentido.