una termine que promises promesas node funciones funciona funcion example esperar ejemplos como await async asincronas javascript node.js asynchronous ecmascript-6 babeljs

javascript - termine - node js async await ejemplos



Llame a funciones asíncronas/en espera en paralelo (9)

La solución intuitiva

function wait(ms, data) { console.log(''Starting task:'', data, ms); return new Promise( resolve => setTimeout(resolve, ms, data) ); } (async function parallel() { // step 1 - initiate all promises console.log(''STARTING'') let task1 = wait(2000, ''parallelTask1'') // PS: see Exception handling below let task2 = wait(500, ''parallelTask2'') let task3 = wait(1000, ''parallelTask3'') // step 2 - await all promises console.log(''WAITING'') task1 = await task1 task2 = await task2 task3 = await task3 // step 3 - all results are 100% ready console.log(''FINISHED'') console.log(''Result:'', task1, task2, task3) })()

  1. Esto ejecutará las promesas una por una, pero al instante y continuarán ejecutándose simultáneamente.
  2. Aquí es donde hacemos una pausa en la ejecución de código adicional y esperamos a que finalicen. No importa el orden y cuál se resuelve primero. El código no continuará con el paso 3 antes de que todos se resuelvan. Si el primero lleva más tiempo, no tendrá que esperar más el segundo, ya que se habría cumplido cuando llegue el código.
  3. Está hecho, la última de las promesas se resolvió y la ejecución del código se completó la última llamada en await .

Con ES6, incluso puede hacer esto en el paso 2, después de la iniciación ejecutada

[task1, task2, task3] = [await task1, await task2, await task3]

PD: también puedes esperar dentro de los cálculos

let five = getAsyncFive() let ten = getAsyncTen() let result = await five * await ten

* tenga en cuenta que no es lo mismo que let result = await getAsyncFive() * await getAsyncTen() ya que esto no ejecutará las tareas asincrónicas en paralelo.

manejo de excepciones

En el fragmento a continuación, el .catch(e => e) detecta un error y permite que la cadena continúe, permitiendo que la promesa se resuelva , en lugar de rechazar . Sin la catch , el código arrojaría una excepción no controlada y la función saldría temprano.

const wait = (ms, data) => log(ms,data) || new Promise( resolve => setTimeout(resolve, ms, data) ) const reject = (ms, data) => log(ms,data) || new Promise( (r, reject) => setTimeout(reject, ms, data) ) const e = e => ''err-'' + e const l = l => (console.log(''Done:'', l), l) const log = (ms, data) => console.log(''Started'', data, ms) ;(async function parallel() { let task1 = reject(500, ''parallelTask1'').catch(e).then(l) let task2 = wait(2000, ''parallelTask2'').catch(e).then(l) let task3 = reject(1000, ''parallelTask3'').catch(e).then(l) console.log(''WAITING'') task1 = await task1 task2 = await task2 task3 = await task3 console.log(''FINISHED'', task1, task2, task3) })()

El segundo fragmento no se maneja y la función fallará.
También puede abrir Devtools y ver los errores en la salida de la consola.

const wait = (ms, data) => log(ms,data) || new Promise( resolve => setTimeout(resolve, ms, data) ) const reject = (ms, data) => log(ms,data) || new Promise( (r, reject) => setTimeout(reject, ms, data) ) const e = e => ''err-'' + e const l = l => (console.log(''Done:'', l), l) const log = (ms, data) => console.log(''Started'', data, ms) console.log(''here1'') ;(async function parallel() { let task1 = reject(500, ''parallelTask1'').then(l) // catch is removed let task2 = wait(2000, ''parallelTask2'').then(l) let task3 = reject(1000, ''parallelTask3'').then(l) console.log(''WAITING'') task1 = await task1 task2 = await task2 task3 = await task3 console.log(''FINISHED'', task1, task2, task3) })() console.log(''here2'') // Note: "FINISHED" will not run

Por lo que yo entiendo, en ES7 / ES2016, poner múltiples en await en el código funcionará de manera similar a encadenar .then() con promesas, lo que significa que se ejecutarán uno tras otro en lugar de en paralelo. Entonces, por ejemplo, tenemos este código:

await someCall(); await anotherCall();

¿Entiendo correctamente que se anotherCall() solo cuando se someCall() ? ¿Cuál es la forma más elegante de llamarlos en paralelo?

Quiero usarlo en Node, ¿tal vez hay una solución con la biblioteca asíncrona?

EDITAR: No estoy satisfecho con la solución proporcionada en esta pregunta: Desaceleración debido a la espera no paralela de promesas en generadores asíncronos , porque usa generadores y estoy preguntando sobre un caso de uso más general.


Creo una función auxiliar waitAll, puede ser que la haga más dulce. Solo funciona en nodejs por ahora, no en el navegador Chrome.

//const parallel = async (...items) => { const waitAll = async (...items) => { //this function does start execution the functions //the execution has been started before running this code here //instead it collects of the result of execution of the functions const temp = []; for (const item of items) { //this is not //temp.push(await item()) //it does wait for the result in series (not in parallel), but //it doesn''t affect the parallel execution of those functions //because they haven started earlier temp.push(await item); } return temp; }; //the async functions are executed in parallel before passed //in the waitAll function //const finalResult = await waitAll(someResult(), anotherResult()); //const finalResult = await parallel(someResult(), anotherResult()); //or const [result1, result2] = await waitAll(someResult(), anotherResult()); //const [result1, result2] = await parallel(someResult(), anotherResult());


Hay otra forma sin Promise.all () para hacerlo en paralelo:

Primero, tenemos 2 funciones para imprimir números:

function printNumber1() { return new Promise((resolve,reject) => { setTimeout(() => { console.log("Number1 is done"); resolve(10); },1000); }); } function printNumber2() { return new Promise((resolve,reject) => { setTimeout(() => { console.log("Number2 is done"); resolve(20); },500); }); }

Esto es secuencial:

async function oneByOne() { const number1 = await printNumber1(); const number2 = await printNumber2(); } //Output: Number1 is done, Number2 is done

Esto es paralelo:

async function inParallel() { const promise1 = printNumber1(); const promise2 = printNumber2(); const number1 = await promise1; const number2 = await promise2; } //Output: Number2 is done, Number1 is done


He creado una esencia que prueba algunas formas diferentes de resolver promesas, con resultados. Puede ser útil ver las opciones que funcionan.


Puedes esperar en Promise.all() :

await Promise.all([someCall(), anotherCall()]);

Para almacenar los resultados:

let [someResult, anotherResult] = await Promise.all([someCall(), anotherCall()]);


Yo voto por:

await Promise.all([someCall(), anotherCall()]);

Tenga en cuenta el momento en que llama a las funciones, puede causar resultados inesperados:

// Supposing anotherCall() will trigger a request to create a new User if (callFirst) { await someCall(); } else { await Promise.all([someCall(), anotherCall()]); // --> create new User here }

Pero el siguiente siempre activa la solicitud para crear un nuevo usuario

// Supposing anotherCall() will trigger a request to create a new User const someResult = someCall(); const anotherResult = anotherCall(); // ->> This always creates new User if (callFirst) { await someCall(); } else { const finalResult = [await someResult, await anotherResult] }


Actualizar:

La respuesta original hace que sea difícil (y en algunos casos imposible) manejar correctamente los rechazos de promesas. La solución correcta es usar Promise.all :

const [someResult, anotherResult] = await Promise.all([someCall(), anotherCall()]);

Respuesta original:

Solo asegúrese de llamar a ambas funciones antes de esperar una:

// Call both functions const somePromise = someCall(); const anotherPromise = anotherCall(); // Await both promises const someResult = await somePromise; const anotherResult = await anotherPromise;


TL; DR

Use Promise.all para las llamadas a funciones paralelas, los comportamientos de respuesta no son correctos cuando se produce el error.

Primero, ejecute todas las llamadas asincrónicas a la vez y obtenga todos los objetos Promise . En segundo lugar, use await en los objetos Promise . De esta manera, mientras espera a que la primera Promise resuelva, las otras llamadas asincrónicas siguen progresando. En general, solo esperará tanto como la llamada asincrónica más lenta. Por ejemplo:

// Begin first call and store promise without waiting const someResult = someCall(); // Begin second call and store promise without waiting const anotherResult = anotherCall(); // Now we await for both results, whose async processes have already been started const finalResult = [await someResult, await anotherResult]; // At this point all calls have been resolved // Now when accessing someResult| anotherResult, // you will have a value instead of a promise

Ejemplo de JSbin: http://jsbin.com/xerifanima/edit?js,console

Advertencia: no importa si las llamadas en await están en la misma línea o en líneas diferentes, siempre que la primera llamada en await ocurra después de todas las llamadas asincrónicas. Ver el comentario de JohnnyHK.

Actualización: esta respuesta tiene un tiempo diferente en el manejo de errores de acuerdo con la respuesta de @ bergi , NO arroja el error cuando ocurre el error, pero después de que se ejecutan todas las promesas. [result1, result2] = Promise.all([async1(), async2()]) el resultado con el consejo de @ jonny: [result1, result2] = Promise.all([async1(), async2()]) , verifique el siguiente fragmento de código

const correctAsync500ms = () => { return new Promise(resolve => { setTimeout(resolve, 500, ''correct500msResult''); }); }; const correctAsync100ms = () => { return new Promise(resolve => { setTimeout(resolve, 100, ''correct100msResult''); }); }; const rejectAsync100ms = () => { return new Promise((resolve, reject) => { setTimeout(reject, 100, ''reject100msError''); }); }; const asyncInArray = async (fun1, fun2) => { const label = ''test async functions in array''; try { console.time(label); const p1 = fun1(); const p2 = fun2(); const result = [await p1, await p2]; console.timeEnd(label); } catch (e) { console.error(''error is'', e); console.timeEnd(label); } }; const asyncInPromiseAll = async (fun1, fun2) => { const label = ''test async functions with Promise.all''; try { console.time(label); let [value1, value2] = await Promise.all([fun1(), fun2()]); console.timeEnd(label); } catch (e) { console.error(''error is'', e); console.timeEnd(label); } }; (async () => { console.group(''async functions without error''); console.log(''async functions without error: start'') await asyncInArray(correctAsync500ms, correctAsync100ms); await asyncInPromiseAll(correctAsync500ms, correctAsync100ms); console.groupEnd(); console.group(''async functions with error''); console.log(''async functions with error: start'') await asyncInArray(correctAsync500ms, rejectAsync100ms); await asyncInPromiseAll(correctAsync500ms, rejectAsync100ms); console.groupEnd(); })();


// A generic test function that can be configured // with an arbitrary delay and to either resolve or reject const test = (delay, resolveSuccessfully) => new Promise((resolve, reject) => setTimeout(() => { console.log(`Done ${ delay }`); resolveSuccessfully ? resolve(`Resolved ${ delay }`) : reject(`Reject ${ delay }`) }, delay)); // Our async handler function const handler = async () => { // Promise 1 runs first, but resolves last const p1 = test(10000, true); // Promise 2 run second, and also resolves const p2 = test(5000, true); // Promise 3 runs last, but completes first (with a rejection) // Note the catch to trap the error immediately const p3 = test(1000, false).catch(e => console.log(e)); // Await all in parallel const r = await Promise.all([p1, p2, p3]); // Display the results console.log(r); }; // Run the handler handler(); /* Done 1000 Reject 1000 Done 5000 Done 10000 */

Si bien la configuración de p1, p2 y p3 no los ejecuta estrictamente en paralelo, no retrasan ninguna ejecución y puede atrapar errores contextuales con una captura.