Tengo una pregunta sobre la Array.forEach
implementación nativa de JavaScript: ¿se comporta de forma asincrónica? Por ejemplo, si llamo:
[many many elements].forEach(function () {lots of work to do})
¿Será esto sin bloqueo?
javascript
arrays
asynchronous
foreach
node.js
R. Gr.
fuente
fuente
Respuestas:
No, está bloqueando. Echa un vistazo a la especificación del algoritmo .
Sin embargo, una implementación quizás más fácil de entender se da en MDN :
Si tiene que ejecutar una gran cantidad de código para cada elemento, debe considerar usar un enfoque diferente:
y luego llamarlo con:
Esto sería sin bloqueo entonces. El ejemplo está tomado de JavaScript de alto rendimiento .
Otra opción podrían ser los trabajadores web .
fuente
forEach
no no bloquear enawait
declaraciones por ejemplo, y usted debe más bien utilizar unfor
bucle: stackoverflow.com/questions/37962880/...await
internasasync
. PeroforEach
no sabe qué son las funciones asíncronas. Tenga en cuenta que las funciones asíncronas son solo funciones que devuelven una promesa. ¿EsperaríaforEach
manejar una promesa devuelta de la devolución de llamada?forEach
ignora completamente el valor de retorno de la devolución de llamada. Solo podría manejar una devolución de llamada asíncrona si fuera asíncrona.Si necesita una versión asíncrona
Array.forEach
y similar, están disponibles en el módulo 'async' de Node.js: http://github.com/caolan/async ... como beneficio adicional, este módulo también funciona en el navegador .fuente
eachSeries
en su lugar.Hay un patrón común para hacer un cálculo realmente pesado en Node que puede ser aplicable a usted ...
El nodo es de un solo subproceso (como una opción de diseño deliberada, consulte ¿Qué es Node.js? ); Esto significa que solo puede utilizar un solo núcleo. Las cajas modernas tienen 8, 16 o incluso más núcleos, por lo que esto podría dejar el 90% de la máquina inactiva. El patrón común para un servicio REST es iniciar un proceso de nodo por núcleo y colocarlos detrás de un equilibrador de carga local como http://nginx.org/ .
Bifurcar a un niño : para lo que está tratando de hacer, hay otro patrón común, bifurcar un proceso de niño para hacer el trabajo pesado. Lo bueno es que el proceso secundario puede hacer cálculos pesados en segundo plano mientras que el proceso principal responde a otros eventos. El problema es que no puede / no debe compartir memoria con este proceso secundario (no sin MUCHAS contorsiones y algún código nativo); Tienes que pasar mensajes. Esto funcionará maravillosamente si el tamaño de sus datos de entrada y salida es pequeño en comparación con el cálculo que debe realizarse. Incluso puede iniciar un proceso hijo de node.js y usar el mismo código que estaba usando anteriormente.
Por ejemplo:
fuente
Array.forEach
está destinado a calcular cosas que no esperan, y no se gana nada haciendo que los cálculos sean asíncronos en un bucle de eventos (los trabajadores web agregan multiprocesamiento, si necesita cómputo multinúcleo). Si desea esperar a que finalicen varias tareas, use un contador, que puede ajustar en una clase de semáforo.fuente
Editar 2018-10-11: Parece que hay una buena posibilidad de que el estándar descrito a continuación no se cumpla, considere la canalización como una alternativa (no se comporta exactamente igual pero los métodos podrían implementarse de manera similar).
Esta es exactamente la razón por la que estoy entusiasmado con es7, en el futuro podrá hacer algo como el código a continuación (algunas de las especificaciones no están completas, así que úselas con precaución, intentaré mantener esto actualizado). Pero, básicamente, utilizando el nuevo operador :: bind, podrá ejecutar un método en un objeto como si el prototipo del objeto contiene el método. por ejemplo, [Object] :: [Method] donde normalmente llamarías a [Object]. [ObjectsMethod]
Tenga en cuenta que para hacer esto hoy (24 de julio-16) y que funcione en todos los navegadores, necesitará transpilar su código para la siguiente funcionalidad: Importar / Exportar , Funciones de flecha , Promesas , Asíncrono / Esperar y lo más importante , enlace de funciones . El siguiente código podría modificarse para usar solo la función bind si es necesario, toda esta funcionalidad está perfectamente disponible hoy en día usando babel .
YourCode.js (donde ' mucho trabajo por hacer ' simplemente debe devolver una promesa, resolviéndola cuando se realiza el trabajo asincrónico).
ArrayExtensions.js
fuente
Esta es una función asíncrona corta para usar sin requerir libs de terceros
fuente
Hay un paquete en npm para asincrónico fácil para cada bucle .
También otra variación para AllAsync
fuente
Es posible codificar incluso la solución como esta, por ejemplo:
Por otro lado, es mucho más lento que un "para".
De lo contrario, la excelente biblioteca Async puede hacer esto: https://caolan.github.io/async/docs.html#each
fuente
Aquí hay un pequeño ejemplo que puede ejecutar para probarlo:
Producirá algo como esto (si toma mucho menos / mucho tiempo, aumenta / disminuye el número de iteraciones):
fuente
Use Promise.each of bluebird library.
Este método itera sobre una matriz, o una promesa de una matriz, que contiene promesas (o una combinación de promesas y valores) con la función iteradora dada con la firma (valor, índice, longitud) donde el valor es el valor resuelto de un promesa respectiva en la matriz de entrada. La iteración ocurre en serie.Si la función de iterador devuelve una promesa o un thenable, entonces se espera el resultado de la promesa antes de continuar con la próxima iteración. Si se rechaza cualquier promesa en la matriz de entrada, también se rechaza la promesa devuelta.
Si todas las iteraciones se resuelven correctamente, Promise.each se resuelve en la matriz original sin modificaciones . Sin embargo, si una iteración rechaza o contiene errores, Promise.each deja de ejecutarse inmediatamente y no procesa más iteraciones. El error o el valor rechazado se devuelve en este caso en lugar de la matriz original.
Este método está destinado a ser utilizado para efectos secundarios.
fuente