Prefacio
Lo más destacado de NodeJS es el modelo de E/S sin bloqueo impulsado por eventos, lo que hace que NodeJs tenga fuertes capacidades de procesamiento de concurrencias y es muy adecuado para escribir aplicaciones de red. La mayoría de las operaciones de E/S en NodeJS son casi asincrónicas, es decir, los resultados de nuestras operaciones de E/S básicamente deben procesarse en la función de devolución de llamada, como la siguiente función que lee el contenido del archivo:
La copia del código es la siguiente:
fs.ReadFile ('/etc/passwd', function (err, data) {
if (err) tirar err;
console.log (datos);
});
Entonces, ¿qué debemos hacer si leemos dos archivos y fusionamos el contenido de estos dos archivos juntos? La mayoría de las personas que no están en contacto con JS pueden hacer esto:
La copia del código es la siguiente:
fs.ReadFile ('/etc/passwd', function (err, data) {
if (err) tirar err;
fs.ReadFile ('/etc/passwd2', function (err, data2) {
if (err) tirar err;
// procesa datos de datos y datos2 aquí
});
});
Si se ocupa de múltiples escenarios similares, ¿no sería que las funciones de devolución de llamada sean anidadas por capa? Esto es lo que la gente a menudo llama la pirámide o el infierno de devolución de llamada (http://callbackhell.com/), y también es el problema más problemático para el novato JS.
Este tipo de código anidado ha traído muchos problemas al desarrollo, principalmente reflejado en:
1. La posibilidad de código empeora
2. Dificultades de depuración
3. Es difícil verificar después de que ocurra una excepción
Este artículo presenta principalmente cómo manejar los problemas de devolución de llamada asincrónicos anteriores.
Solución primaria: procese recursivamente las devoluciones de llamada asincrónicas
Podemos usar la recursión como la herramienta de control de ejecución para el código. Encapsula las operaciones que deben ejecutarse en una función y controlar el proceso de ejecución del código llamando recursivamente en la función de devolución de llamada. Sin más preámbulos, hablemos de tonterías, echemos un vistazo al código anterior:
La copia del código es la siguiente:
var fs = require ('fs');
// Lista de archivos a procesar
var files = ['file1', 'file2', 'file3'];
función parsefile () {
if (files.length == 0) {
devolver;
}
var file = files.hift ();
fs.ReadFile (archivo, function (err, data) {
// Procesar datos de archivo aquí
parsefile (); // Después del procesamiento, procese el siguiente archivo a través de una llamada recursiva
});
}
// comienza a procesar
parsefile ();
El código anterior ha procesado los archivos en la matriz a su vez como ejemplo, introduciendo el proceso de ejecución de control del código a través de medios recursivos.
Es bueno aplicarlo a algunos escenarios simples, como: podemos usar este método guardando los datos en una matriz en la base de datos a su vez.
Recursivamente, se pueden resolver algunos problemas simples de devolución de llamada asincrónica. Sin embargo, todavía parece impotente lidiar con complejas devoluciones de llamada asincrónicas (como sincronizar los resultados de múltiples operaciones asíncronas).
Hermoso punto: use bibliotecas de terceros como Async, Q, prometa manejar devoluciones de llamada asincrónicas
Para manejar mejor las devoluciones de llamada anidadas, puede considerar usar algunas bibliotecas de terceros que tratan específicamente con asíncrono. Por supuesto, si tiene la capacidad, puede escribir una herramienta auxiliar para el procesamiento asíncrono usted mismo.
Las bibliotecas más utilizadas para manejar el procesamiento asíncrono son: Async, Q y Promise. A juzgar por el sitio web npmjs.org, Async es el más popular. He usado Async antes, y de hecho es bastante conveniente, y varios flujos de control de procesamiento asíncrono se implementan bien.
Usaremos async para procesar el código que inicialmente lee dos archivos al mismo tiempo, como se muestra a continuación:
La copia del código es la siguiente:
var async = request ('async')
, fs = requerir ('fs');
async.parallel ([[
función (devolución de llamada) {
fs.ReadFile ('/etc/passwd', function (err, data) {
if (err) llamada de llamada (err);
devolución de llamada (nulo, datos);
});
},
función (devolución de llamada) {
fs.ReadFile ('/etc/passwd2', function (err, data2) {
if (err) llamada de llamada (err);
devolución de llamada (nulo, data2);
});
}
]
función (err, resultados) {
// procesa datos de datos y datos2 aquí, y el contenido de cada archivo se obtiene de los resultados
});
A través del módulo Async, el proceso de ejecución asíncrono puede estar bien controlado, lo que también puede resolver el problema de las devoluciones de llamada en capas. El código es más claro que antes, pero aún no se puede separar de la función de devolución de llamada.
Piénselo, sería genial si puede manejar asíncrono sin usar funciones de devolución de llamada. A continuación, hablemos sobre el uso de las nuevas características de ES6 para lograr este objetivo.
Elegant Point: Abrace ES6, reemplace las funciones de devolución de llamada y resuelva el problema del infierno de devolución de llamada
Por cierto, Ecmascript Harmony (ES6) ha introducido muchas características nuevas en JS. Los estudiantes que no saben mucho sobre ES6 pueden ver por su cuenta.
Para usar las nuevas características de ES6 en NodeJS, debe usar V0.11.x o más.
Este artículo presenta el uso de la función Generator en lugar de las funciones de devolución de llamada. ¿No sabes sobre Generator? Puedes verlo aquí.
Aquí usamos dos módulos CO y Thunkify, y usamos el comando de instalación de NPM para instalarlo.
Tome el problema mencionado al comienzo de este artículo como ejemplo. El código de ejemplo que usa la función del generador es el siguiente:
La copia del código es la siguiente:
var fs = requirir ('fs')
, CO = requerir ('co')
, thunkify = request ('Thunkify');
var readfile = Thunkify (fs.ReadFile);
CO (function *() {
var test1 = rendimiento de readfile ('test1.txt');
var test2 = rendimiento de readfile ('test2.txt');
var test = test1.ToString () + test2.ToString ();
console.log (prueba);
}) ();
También es muy simple manejar excepciones en el código, solo hágalo de esta manera:
La copia del código es la siguiente:
intentar {
var test1 = rendimiento de readfile ('test1.txt');
} catch (e) {
// manejar excepciones aquí
}
¿Es este tipo de código mucho más elegante? ¿No es genial manejar asincrónicamente como escribir código síncrono?
El marco más popular para el desarrollo web en el campo NodeJS es expreso. Vale la pena mencionar que el miembro central de Express TJ, el Gran Maestro de Express, ha dirigido un nuevo marco web: KOA, que afirma ser la próxima generación de marco de desarrollo web. KOA realmente utiliza la función del generador ES6 para ayudarnos a evitar caer en capas de devoluciones de llamada al desarrollar el sistema web.
Resumir
Cita una oración de la promoción del proyecto FIBJS: menos devolución de llamada, más chicas: menos devoluciones de llamada, más chicas