Resolviendo problemas de devolución de llamada con Async

Cuando empezamos a programar, aprendemos que un bloque de código se ejecuta de arriba a abajo. Esta es una programación síncrona: cada operación se completa antes de que comience la siguiente. Esto es genial cuando haces muchas cosas que prácticamente no requieren tiempo para completar una computadora, como agregar números, manipular una cadena o asignar variables. 

¿Qué sucede cuando desea hacer algo que demora un tiempo relativamente largo, como acceder a un archivo en el disco, enviar una solicitud de red o esperar a que transcurra un temporizador? En la programación síncrona, su script no puede hacer nada más mientras espera. 

Esto podría estar bien para algo simple o en una situación en la que tendrá varias instancias de su script en ejecución, pero para muchas aplicaciones de servidor, es una pesadilla.. 

Entrar en la programación asíncrona. En una secuencia de comandos asíncrona, su código continúa ejecutándose mientras espera que algo suceda, pero puede retroceder cuando ha ocurrido algo.. 

Tomemos, por ejemplo, una solicitud de red. Si realiza una solicitud de red a un servidor lento que tarda tres segundos en responder, su secuencia de comandos puede estar haciendo otras cosas de forma activa mientras este servidor lento responde. En este caso, tres segundos pueden no parecer mucho para un humano, pero un servidor podría responder a miles de otras solicitudes mientras espera. Entonces, ¿cómo manejar la asincronía en Node.js? 

La forma más básica es a través de una devolución de llamada. Una devolución de llamada es solo una función que se llama cuando se completa una operación asíncrona. Por convención, las funciones de devolución de llamada de Node.js tienen al menos un argumento, errar. Las devoluciones de llamada pueden tener más argumentos (que generalmente representan los datos devueltos a la devolución de llamada), pero el primero será errar. Como habrás adivinado, errar contiene un objeto de error (si se ha activado un error, más sobre eso más adelante).

Echemos un vistazo a un ejemplo muy simple. Usaremos el módulo del sistema de archivos integrado de Node.js (fs). En este script, leeremos el contenido de un archivo de texto. La última línea del archivo es una console.log eso plantea una pregunta: si ejecuta este script, ¿cree que verá el registro antes de que veamos el contenido del archivo de texto??

var fs = require ('fs'); fs.readFile ('a-text-file.txt', // el nombre de archivo de un archivo de texto que dice "Hello!" 'utf8', // la codificación del archivo, en este caso, la función utf-8 (err , texto) // la devolución de llamada console.log ('Error:', err); // Errores, si hay alguno console.log ('Texto:', texto); // el contenido del archivo); // ¿Será esto antes o después del Error / Texto? console.log ('¿Se registra esto antes o después de los contenidos del archivo de texto?'); 

Como esto es asíncrono, veremos el último console.log antes de El contenido del archivo de texto. Si tienes un archivo llamado a-text-file.txt en el mismo directorio en el que está ejecutando su script de nodo, verá que errar es nulo, y el valor de texto Se rellena con el contenido del archivo de texto.. 

Si no tienes un archivo llamado a-text-file.txt, errar devolverá un objeto de error, y el valor de texto estarán indefinido. Esto lleva a un aspecto importante de las devoluciones de llamada: siempre debe manejar sus errores. Para manejar errores, necesita verificar un valor en el errarvariable; si un valor está presente, entonces se produjo un error. Por convención, errar los argumentos usualmente no regresan falso, para que solo puedas comprobar la veracidad.

var fs = require ('fs'); fs.readFile ('a-text-file.txt', // el nombre de archivo de un archivo de texto que dice "Hello!" 'utf8', // la codificación del archivo, en este caso, la función utf-8 (err , texto) // la devolución de llamada if (err) console.error (err); // muestra un error en la consola else console.log ('Text:', text); // no hay error, así que muestre el contenido del archivo);

Ahora, supongamos que desea mostrar el contenido de dos archivos en un orden particular. Terminarás con algo como esto:

var fs = require ('fs'); fs.readFile ('a-text-file.txt', // el nombre de archivo de un archivo de texto que dice "Hello!" 'utf8', // la codificación del archivo, en este caso, la función utf-8 (err , texto) // la devolución de llamada if (err) console.error (err); // muestra un error en la consola else console.log ('Primer archivo de texto:', texto); // no hay error, así que muestre el contenido del archivo fs.readFile ('another-text-file.txt', // el nombre de archivo de un archivo de texto que dice "¡Hola!" 'utf8', // la codificación del archivo, en este caso , función utf-8 (err, texto) // la devolución de llamada if (err) console.error (err); // muestra un error en la consola else console.log ('Segundo archivo de texto:', texto ); // no hay error, por lo que muestra el contenido del archivo););

El código parece bastante desagradable y tiene una serie de problemas:

  1. Estás cargando los archivos secuencialmente; sería más eficiente si pudiera cargarlos ambos al mismo tiempo y devolver los valores cuando ambos se hayan cargado completamente.

  2. Sintácticamente es correcto pero difícil de leer. Observe el número de funciones anidadas y las pestañas en aumento. Podría hacer algunos trucos para que se vea un poco mejor, pero puede estar sacrificando la legibilidad de otras maneras..

  3. No es un propósito muy general. Esto funciona bien para dos archivos, pero ¿qué pasaría si tuviera nueve archivos a veces y otras veces 22 o solo uno? La forma en que está escrito actualmente es muy rígida..

No se preocupe, podemos resolver todos estos problemas (y más) con async.js.

Devoluciones de llamada con async.js

Primero, comencemos instalando el módulo async.js.

npm instalar async --save

Async.js se puede utilizar para pegar conjuntos de funciones en serie o en paralelo. Reescribamos nuestro ejemplo:

var async = require ('async'), //async.js module fs = require ('fs'); async.series (// ejecuta las funciones en el primer argumento, una tras otra [// El primer argumento es una matriz de funciones function (cb) // 'cb' es una abreviatura de "callback" fs.readFile ('a- text-file.txt ',' utf8 ', cb);, function (cb) fs.readFile (' another-text-file.txt ',' utf8 ', cb);], function (err, valores ) // La devolución de llamada "hecha" que se ejecuta después de que las funciones de la matriz se hayan completado si (err) // Si ocurrieron errores al ejecutar las funciones de la matriz, se enviarán como error. Console.error ( err); else // Si err es falso, entonces todo es bueno console.log ('Primer archivo de texto:', valores [0]); console.log ('Segundo archivo de texto:', valores [1]); );

Esto funciona casi igual que en el ejemplo anterior, cargando secuencialmente cada archivo, y difiere solo en que lee cada archivo y no muestra el resultado hasta que se completa. El código es más conciso y limpio que el ejemplo anterior (y lo mejoraremos más adelante). async.series toma una serie de funciones y las ejecuta una tras otra. 

Cada función debe tener un solo argumento, la devolución de llamada (o cb en nuestro código). cbdeben ejecutarse con el mismo tipo de argumentos que cualquier otra devolución de llamada, para que podamos incluirla en nuestro fs.readFile argumentos. 

Finalmente, los resultados se envían a la devolución de llamada final, el segundo argumento en para async.series. Los resultados se almacenan en una matriz con los valores correlacionados con el orden de las funciones en el primer argumento de async.series.

Con async.js, el manejo de errores se simplifica porque si encuentra un error, devuelve el error al argumento de la devolución de llamada final y no ejecutará ninguna otra función asíncrona.. 

Todos juntos ahora

Una función relacionada es async.parallel; tiene los mismos argumentos que async.series para que pueda cambiar entre los dos sin alterar el resto de su sintaxis. Este es un buen punto para cubrir paralelo y concurrente. 

JavaScript es básicamente un lenguaje de un solo hilo, lo que significa que solo puede hacer una cosa a la vez. Es capaz de realizar algunas tareas en un subproceso separado (la mayoría de las funciones de E / S, por ejemplo), y aquí es donde la programación asíncrona entra en juego con JS. No confundir paralelo con concurrencia

Cuando ejecutas dos cosas con async.parallel, no lo estás haciendo abrir otro hilo para analizar JavaScript o hacer dos cosas a la vez: estás realmente controlando cuándo pasa entre las funciones en el primer argumento de async.parallel. Por lo tanto, no gana nada simplemente poniendo el código síncrono en async.parallel. 

Esto se explica mejor visualmente:

Aquí está nuestro ejemplo anterior escrito para ser paralelo, la única diferencia es que usamos async.parallel más bien que async.series.

var async = require ('async'), //async.js module fs = require ('fs'); async.parallel (// ejecuta las funciones en el primer argumento, pero no esperes a que la primera función termine para iniciar el segundo [// El primer argumento es una matriz de funciones function (cb) // 'cb' es la abreviatura de "callback" fs.readFile ('a-text-file.txt', 'utf8', cb);, function (cb) fs.readFile ('another-text-file.txt', 'utf8 ', cb);], función (err, valores) // La devolución de llamada "hecha" que se ejecuta después de que las funciones de la matriz se hayan completado si (err) // Si se produjeron errores al ejecutar las funciones en la matriz , se enviarán como err. console.error (err); else // Si err es falsy, entonces todo es bueno console.log ('Primer archivo de texto:', valores [0]); console.log ( 'Segundo archivo de texto:', valores [1]););

Una y otra vez

Nuestros ejemplos anteriores han ejecutado un número fijo de operaciones, pero ¿qué sucede si necesita un número variable de operaciones asíncronas? Esto se complica rápidamente si solo confía en las devoluciones de llamada y en la construcción de lenguaje regular, confiando en contadores torpes o verificaciones de condiciones que ocultan el significado real de su código. Echemos un vistazo al equivalente aproximado de un bucle for con async.js.

En este ejemplo, escribiremos diez archivos en el directorio actual con nombres de archivos secuenciales y algunos contenidos breves. Puede variar el número cambiando el valor del primer argumento de async.times. En este ejemplo, la devolución de llamada para fs.writeFile solo crea un errar argumento, pero el async.times La función también puede soportar un valor de retorno. Al igual que async.series, se pasa a la devolución de llamada realizada en el segundo argumento como una matriz.

var async = require ('async'), fs = require ('fs'); async.times (10, // número de veces para ejecutar la función function (runCount, callback) fs.writeFile ('file -' + runCount + '. txt', // el nuevo nombre de archivo 'Este es el número de archivo' + runCount, // el contenido de la nueva devolución de llamada del archivo);, function (err) if (err) console.error (err); else console.log ('Wrote files.'););

Es un buen momento para decir que la mayoría de las funciones async.js, de forma predeterminada, se ejecutan en paralelo en lugar de en serie. Entonces, en el ejemplo anterior, comenzará a crear los archivos e informes cuando todos estén completamente creados y escritos.. 

Las funciones que se ejecutan en paralelo de manera predeterminada tienen una función de serie de corolario indicada por la función que termina con, usted lo adivinó, 'Serie'. Entonces, si desea ejecutar este ejemplo en serie en lugar de en paralelo, cambiaría async.times a async.timesSeries.

Para nuestro próximo ejemplo de bucle, echaremos un vistazo a la función async.until. async.until ejecuta una función asíncrona (en serie) hasta que se cumple una condición particular. Esta función toma tres funciones como argumentos.. 

La primera función es la prueba en la que devuelve verdadero (si desea detener el bucle) o falso (si desea continuar el bucle). El segundo argumento es la función asíncrona, y el final es la devolución de llamada realizada. Echale un vistazo a éste ejemplo:

var async = require ('async'), fs = require ('fs'), startTime = new Date (). getTime (), // la marca de tiempo de Unix en milisegundos runCount = 0; async.until (function () // devuelve true si han transcurrido 4 milisegundos, de lo contrario false (y continúa ejecutando el script) devuelve una nueva Fecha (). getTime ()> (startTime + 5);, function (callback)  runCount + = 1; fs.writeFile ('timed-file -' + runCount + '. txt', // el nuevo nombre de archivo 'Este es el número de archivo' + runCount, // el contenido de la nueva devolución de llamada del archivo);, function (err) if (err) console.error (err); else console.log ('Wrote files.'););

Este script creará nuevos archivos de texto durante cinco milisegundos. Al comienzo del script, obtenemos la hora de inicio en la época de milisegundos de Unix, y luego en la función de prueba obtenemos la hora actual y la prueba para ver si es cinco milisegundos mayor que la hora de inicio más cinco. Si ejecuta este script varias veces, puede obtener resultados diferentes. 

En mi máquina, estaba creando entre 6 y 20 archivos en cinco milisegundos. Curiosamente, si intentas añadir console.log Ya sea en la función de prueba o en la función asíncrona, obtendrá resultados muy diferentes porque le lleva tiempo escribir en la consola. Simplemente muestra que en el software, todo tiene un costo de rendimiento.!

El para cada bucle es una estructura útil: le permite hacer algo para cada elemento de una matriz. En async.js, este sería el async.each función. Esta función toma tres argumentos: la colección o la matriz, la función asincrónica que se debe realizar para cada elemento y la devolución de llamada realizada. 

En el ejemplo a continuación, tomamos una serie de cadenas (en este caso, los tipos de razas de perros del sighthound) y creamos un archivo para cada cadena. Cuando se han creado todos los archivos, se ejecuta la devolución de llamada realizada. Como es de esperar, los errores se manejan a través de errar objeto en la devolución de llamada hecha. async.each se ejecuta en paralelo, pero si desea ejecutarlo en serie, puede seguir el patrón mencionado anteriormente y usar async.eachSeries en lugar de async.each.

var async = require ('async'), fs = require ('fs'); async.each (// una variedad de razas de perros de la familia de perros ['greyhound', 'saluki', 'borzoi', 'galga', 'podenco', 'whippet', 'lurcher', 'italian-greyhound'], dogBreed, callback) fs.writeFile (dogBreed + '. txt', // el nuevo nombre de archivo 'para los perros de la raza' + dogBreed, // el contenido del nuevo callback);, function (err)  if (err) console.error (err); else console.log ('Hecho de escribir archivos sobre perros.'););

Un primo de async.each es el async.map función; la diferencia es que puede devolver los valores a la devolución de llamada realizada. Con el async.map función, usted pasa una matriz o colección como primer argumento, y luego se ejecutará una función asíncrona en cada elemento de la matriz o colección. El último argumento es el callback realizado.. 

El siguiente ejemplo toma la variedad de razas de perros y utiliza cada elemento para crear un nombre de archivo. El nombre del archivo se pasa a fs.readFile, donde se lee y los valores son devueltos por la función de devolución de llamada. Usted termina con una matriz del contenido del archivo en los argumentos de devolución de llamada realizados.

var async = require ('async'), fs = require ('fs'); async.map (['greyhound', 'saluki', 'borzoi', 'galga', 'podenco', 'whippet', 'lurcher', 'italian-greyhound'], función (dogBreed, callback) fs.readFile (dogBreed + '. txt', // el nuevo nombre de archivo 'utf8', devolución de llamada);, function (err, dogBreedFileContents) if (err) console.error (err); else else console.log ('dog razas '); console.log (dogBreedFileContents););

filtro async. También es muy similar en sintaxis a async.each y async.map, pero con el filtro usted envía un valor booleano a la devolución de llamada del elemento en lugar del valor del archivo. En la devolución de llamada realizada, obtiene una nueva matriz, con solo los elementos que ha pasado cierto o valor de verdad para en la devolución de llamada del artículo. 

var async = require ('async'), fs = require ('fs'); async.filter (['greyhound', 'saluki', 'borzoi', 'galga', 'podenco', 'whippet', 'lurcher', 'italian-greyhound'], función (dogBreed, callback) fs.readFile (dogBreed + '. txt', // el nuevo nombre de archivo 'utf8', función (err, fileContents) if (err) callback (err); else callback (err, // esto será falso ya que verificamos encima de fileContents.match (/ greyhound / gi) // use RegExp para verificar la cadena 'greyhound' en el contenido del archivo););, function (err, dogBreedFileContents) if (err) console .error (err); else console.log ('' galgos cría: '); console.log (dogBreedFileContents););

En este ejemplo, estamos haciendo algunas cosas más que en los ejemplos anteriores. Observe cómo estamos agregando una llamada de función adicional y manejando nuestro propio error. los Si errar y devolución de llamada El patrón es muy útil si necesita manipular los resultados de una función asíncrona, pero aún así desea que async.js maneje los errores.. 

Además, notará que estamos usando la variable err como el primer argumento de la función de devolución de llamada. A primera vista, esto no se ve del todo bien. Pero como ya hemos comprobado la veracidad del error, sabemos que es falso y seguro pasar a la devolución de llamada.. 

Sobre el borde de un acantilado

Hasta ahora, hemos explorado una serie de bloques de construcción útiles que tienen corolarios aproximados en la programación síncrona. Vamos a sumergirnos en async.waterfall, Lo que no tiene mucho equivalente en el mundo sincrónico.. 

El concepto con una cascada es que los resultados de una función asíncrona fluyen en los argumentos de otra función asíncrona en serie. Es un concepto muy poderoso, especialmente cuando se trata de unir varias funciones asíncronas que se basan entre sí. Con async.waterfall, el primer argumento es una serie de funciones, y el segundo argumento es su devolución de llamada hecha. 

En su conjunto de funciones, la primera función siempre comenzará con un solo argumento, la devolución de llamada. Cada función subsiguiente debe coincidir con los argumentos no errados de la función anterior, sin la función err y con la adición de la nueva devolución de llamada.

En nuestro siguiente ejemplo, comenzaremos a combinar algunos conceptos usando cascada como pegamento. En la matriz que es el primer argumento, tenemos tres funciones: la primera carga la lista de directorios del directorio actual, la segunda toma la lista de directorios y utiliza async.map correr fs.stat en cada archivo, y la tercera función toma la lista de directorios del primer resultado de la función y obtiene el contenido de cada archivo (fs.readFile).

async.waterfall ejecuta cada función secuencialmente, por lo que siempre se ejecutará toda la fs.stat funciona antes de ejecutar cualquier fs.readFile. En este primer ejemplo, las funciones segunda y tercera no dependen una de la otra, por lo que podrían incluirse en una async.parallel para reducir el tiempo total de ejecución, pero modificaremos esta estructura nuevamente para el siguiente ejemplo.

Nota: Ejecute este ejemplo en un pequeño directorio de archivos de texto, de lo contrario, obtendrá mucha basura durante mucho tiempo en la ventana de su terminal.

var async = require ('async'), fs = require ('fs'); async.waterfall ([function (callback) fs.readdir ('.', callback); // lee el directorio actual, pásalo a la siguiente función., function (fileNames, callback) // 'fileNames' es el listado de directorios de la función anterior async.map (fileNames, // El listado de directorios es solo una matriz de nombres de archivos, fs.stat, // por lo que podemos usar async.map para ejecutar fs.stat para cada función de nombre de archivo (err , stats) if (err) callback (err); else callback (err, fileNames, stats); // pasa el error, la lista del directorio y la colección de estadísticas al siguiente elemento en la cascada) ;, function (fileNames, stats, callback) // la lista del directorio, 'fileNames' está unida a la colección de objetos fs.stat en 'stats' async.map (fileNames, function (aFileName, readCallback) // Esta vez vamos a tomar los nombres de archivo con map y pasarlos a fs.readFile para obtener el contenido fs.readFile (aFileName, 'utf8', readCallback);, function (err, contents) if (err) callback (err); else // Ahora nuestro callback w tengo tres argumentos, la lista de directorios original ('fileNames'), la colección fs.stats y una matriz de con el contenido de cada devolución de llamada del archivo (err, fileNames, stats, contents); ); ], función (err, fileNames, stats, contenidos) if (err) console.error (err);  else console.log (fileNames); console.log (stats); console.log (contenidos); );

Digamos que queremos obtener los resultados de solo los archivos que tienen un tamaño superior a 500 bytes. Podríamos usar el código anterior, pero obtendría el tamaño y el contenido de cada archivo, ya sea que los necesite o no. ¿Cómo podría obtener la estadística de los archivos y solo el contenido de los archivos que cumplen con los requisitos de tamaño?? 

Primero, podemos extraer todas las funciones anónimas en funciones nombradas. Es una preferencia personal, pero hace que el código sea un poco más limpio y más fácil de entender (reutilizable para iniciar). Como puede imaginar, deberá obtener los tamaños, evaluar esos tamaños y obtener solo el contenido de los archivos por encima del requisito de tamaño. Esto se puede lograr fácilmente con algo como Array.filter, pero esa es una función síncrona, y async.waterfall espera funciones de estilo asíncrono. Async.js tiene una función auxiliar que puede envolver funciones síncronas en funciones asíncronas, el nombre más bien jazzily async.asyncify.

Tenemos que hacer tres cosas, todas las cuales vamos a terminar con async.asyncify. Primero, tomaremos el nombre y las matrices de estadísticas del arrayFsStat función, y los fusionaremos utilizando mapa. Luego filtraremos cualquier elemento que tenga un tamaño de estadística inferior a 300. Finalmente, tomaremos el nombre de archivo y el objeto estadístico combinados y los usaremos mapa de nuevo para simplemente sacar el nombre de archivo. 

Una vez que tengamos los nombres de los archivos con un tamaño inferior a 300, usaremos async.map y fs.readFile para obtener los contenidos. Hay muchas formas de romper este huevo, pero en nuestro caso se rompió para mostrar la máxima flexibilidad y la reutilización del código. Esta async.waterfall El uso ilustra cómo se pueden mezclar y combinar códigos síncronos y asíncronos..

var async = require ('async'), fs = require ('fs'); // Nuestro refactorizado anónimo en funciones nombradas directoryListing (callback) fs.readdir ('.', Callback);  function arrayFsStat (fileNames, callback) async.map (fileNames, fs.stat, function (err, stats) if (err) callback (err); else callback (err, fileNames, stats); );  function arrayFsReadFile (fileNames, callback) async.map (fileNames, function (aFileName, readCallback) fs.readFile (aFileName, 'utf8', readCallback);, function (err, contents) if (err) callback (err); else callback (err, contents););  // Estas funciones son funciones síncronas mergeFilenameAndStat (fileNames, stats) return stats.map (function (aStatObj, index) aStatObj.fileName = fileNames [index]; return aStatObj;);  función por encima de 300 (combinedFilenamesAndStats) return combinedFilenamesAndStats .filter (function (aStatObj) return aStatObj.size> = 300;);  function justFilenames (combinedFilenamesAndStats) return combinedFilenamesAndStats .map (function (aCombinedFileNameAndStatObj) return aCombinedFileNameAndStatObj.fileName;);  async.waterfall ([directoryListing, arrayFsStat, async.asyncify (mergeFilenameAndStat), // asyncify envuelve las funciones síncronas en un primer error de devolución de async.asyncify (anterior300), async.asyncify (justFilenames), arrayFRReadArchivo], función contenidos) if (err) console.error (err); else console.log (contents););

Dando un paso más allá, refinemos aún más nuestra función. Digamos que queremos escribir una función que funcione exactamente igual que arriba, pero con la flexibilidad de buscar en cualquier camino. Un primo cercano a async.waterfall es async.seq. Mientras async.waterfall solo ejecuta una cascada de funciones, async.seq devuelve una función que realiza una cascada de otras funciones. Además de crear una función, puede pasar valores que irán a la primera función asíncrona.. 

Convertir a async.seq Solo toma algunas modificaciones. Primero, modificaremos lista de directorios Para aceptar un argumento, este será el camino. En segundo lugar, agregaremos una variable para mantener nuestra nueva función (directoriobajo300). En tercer lugar, vamos a tomar el argumento de la matriz async.waterfall y traducir eso en argumentos para async.seq. Nuestro callback realizado para la cascada ahora se usa como callback hecho cuando ejecutamos directoriobajo300.

var async = require ('async'), fs = require ('fs'), directoryAbove300; function directoryListing (initialPath, callback) // podemos pasar una variable a la primera función utilizada en async.seq - la función resultante puede aceptar argumentos y pasarles esta primera función fs.readdir (initialPath, callback);  function arrayFsStat (fileNames, callback) async.map (fileNames, fs.stat, function (err, stats) if (err) callback (err); else callback (err, fileNames, stats); );  function arrayFsReadFile (fileNames, callback) async.map (fileNames, function (aFileName, readCallback) fs.readFile (aFileName, 'utf8', readCallback);, function (err, contents) if (err) callback (err); else callback (err, contents););  function mergeFilenameAndStat (fileNames, stats) return stats.map (function (aStatObj, index) aStatObj.fileName = fileNames [index]; return aStatObj;);  función por encima de 300 (combinedFilenamesAndStats) return combinedFilenamesAndStats .filter (function (aStatObj) return aStatObj.size> = 300;);  function justFilenames (combinedFilenamesAndStats) return combinadoFilenamesAndStats .map (function (aCombinedFileNameAndStatObj) return aCombinedFileNameAndStatObj.fileName por lo que es, por ejemplo, una de las siguientes personas: arrayFsStat, async.asyncify (mergeFilenameAndStat), async.asyncify (anterior300), async.asyncify (justFilenames), arrayFsReadFile); directoryAbove300 ('.', function (err, fileNames, stats, contents) if (err) console.error (err); else console.log (fileNames););

Una nota sobre promesas y funciones asíncronas

Quizás te preguntes por qué no he mencionado promesas. No tengo nada en contra de ellos, son bastante prácticos y quizás una solución más elegante que las devoluciones de llamada, pero son una forma diferente de ver la codificación asíncrona.. 

Uso de módulos Node.js incorporados errar-Las primeras devoluciones de llamada y miles de otros módulos utilizan este patrón. De hecho, es por eso que este tutorial usa. fs en los ejemplos, algo tan fundamental como el acceso al sistema de archivos en Node.js utiliza devoluciones de llamada, por lo que la manipulación de códigos de devolución de llamada sin promesas es una parte esencial de la programación de Node.js.  

Es posible usar algo como Bluebird para incluir las devoluciones de llamada erróneas primero en funciones basadas en Promesa, pero eso solo le permite llegar tan lejos. Async.js proporciona una gran cantidad de metáforas que hacen que el código asíncrono sea legible y manejable..

Abrazar la asincronía

JavaScript se ha convertido en uno de los lenguajes de facto de trabajar en la web. No deja de tener sus curvas de aprendizaje, y también hay muchos marcos y bibliotecas para mantenerte ocupado. Si está buscando recursos adicionales para estudiar o usar en su trabajo, vea lo que tenemos disponible en el mercado de Envato.

Pero aprender de forma asíncrona es algo completamente diferente y, con suerte, este tutorial le ha mostrado lo útil que puede ser..

La asincronía es la clave para escribir JavaScript del lado del servidor; sin embargo, si no está diseñado correctamente, su código puede convertirse en una bestia incontenible de devoluciones de llamada. Al usar una biblioteca como async.js que proporciona varias metáforas, es posible que la escritura de código asíncrono sea una alegría.