C贸mo trabajar con async / await en bucles JavaScript

驴C贸mo ejecutar bucles as铆ncronos en orden o en paralelo en JavaScript?


Antes de hacer magia asincr贸nica, quiero recordarte c贸mo son los bucles sincr贸nicos cl谩sicos.


Bucles sincr贸nicos


Hace mucho tiempo escrib铆 bucles de esta manera (tal vez t煤 tambi茅n):


for (var i=0; i < array.length; i++) { var item = array[i]; //  -  item } 

Este ciclo es bueno y r谩pido. Pero tiene muchos problemas con la legibilidad y el apoyo. Despu茅s de un tiempo, me acostumbr茅 a su mejor versi贸n:


 array.forEach((item) => { //  -  item }); 

JavaScript se est谩 desarrollando muy r谩pido. Aparecen nuevas caracter铆sticas y sintaxis. Una de mis mejoras favoritas es async / wait .


Ahora uso esta sintaxis con bastante frecuencia. Y a veces hay situaciones en las que necesito hacer algo con elementos de matriz de forma asincr贸nica.


Bucles asincr贸nicos


驴C贸mo usar await en el cuerpo del bucle? Tratemos de escribir una funci贸n asincr贸nica y esperemos la tarea de procesar cada elemento:


 async function processArray(array) { array.forEach(item => { //       //     ! await func(item); }) } 

Este c贸digo arrojar谩 un error. Por qu茅 Porque no podemos usar await dentro de una funci贸n s铆ncrona. Como puede ver, processArray es una funci贸n asincr贸nica. Pero la funci贸n an贸nima que usamos para forEach es sincr贸nica .


驴Qu茅 se puede hacer al respecto?


1. No espere el resultado de la ejecuci贸n.


Podemos definir una funci贸n an贸nima como as铆ncrona:


 async function processArray(array) { array.forEach(async (item) => { await func(item); }) console.log('Done!'); } 

Pero forEach no esperar谩 a que se complete la tarea. forEach es una operaci贸n s铆ncrona. Ella simplemente iniciar谩 las tareas y seguir谩 adelante. Veamos una prueba simple:


 function delay() { return new Promise(resolve => setTimeout(resolve, 300)); } async function delayedLog(item) { //    await  Promise //    delay await delay(); console.log(item); } async function processArray(array) { array.forEach(async (item) => { await delayedLog(item); }) console.log('Done!'); } processArray([1, 2, 3]); 

En la consola veremos:


 Done! 1 2 3 

En algunas situaciones, esto puede ser un resultado normal. Pero a煤n as铆, en la mayor铆a de los casos, esta no es una l贸gica adecuada.


2. Procesando el ciclo secuencialmente


Para esperar el resultado de la ejecuci贸n del cuerpo del bucle, necesitamos volver al viejo bucle "for". Pero esta vez usaremos su nueva versi贸n con for..of construct (Gracias al Protocolo de iteraci贸n ):


 async function processArray(array) { for (const item of array) { await delayedLog(item); } console.log('Done!'); } 

Esto nos dar谩 el resultado esperado:


 1 2 3 Done! 

Cada elemento de la matriz se procesar谩 secuencialmente. 隆Pero podemos ejecutar el ciclo en paralelo!


3. Procesando el ciclo en paralelo


Debe modificar ligeramente el c贸digo para iniciar las operaciones en paralelo:


 async function processArray(array) { //  "map"    const promises = array.map(delayedLog); //       await Promise.all(promises); console.log('Done!'); } 

Este c贸digo puede ejecutar varias tareas de delayLog en paralelo. Pero tenga cuidado con las grandes matrices. Demasiadas tareas pueden ser demasiado dif铆ciles para la CPU y la memoria.


Adem谩s, no confunda las "tareas paralelas" del ejemplo con paralelismo y subprocesos reales. Este c贸digo no garantiza la ejecuci贸n paralela. Todo depende del cuerpo del bucle (en el ejemplo, se delayedLog ). Las solicitudes de red, los trabajadores web y algunas otras tareas se pueden realizar en paralelo.

Source: https://habr.com/ru/post/es435084/


All Articles