Durante el proceso de escritura Node.js, las operaciones continuas de IO pueden conducir a "pesadilla piramidal". La anidación múltiple de las funciones de devolución de llamada dificulta el código de mantener. La promesa de CommonJS se usa para encapsular las funciones asincrónicas y usar una API de cadena unificada para deshacerse de la pesadilla de múltiples devoluciones de llamada.
El modelo IO sin bloqueo proporcionado por Node.js nos permite usar funciones de devolución de llamada para manejar las operaciones de IO, pero cuando se requieren operaciones continuas de IO, sus funciones de devolución de llamada se anidarán varias veces, el código no es hermoso, y no es fácil de mantener, y puede haber muchos códigos repetidos para el manejo de errores, que es el "Pyramid of Doom".
La copia del código es la siguiente:
step1 (function (value1) {
step2 (value1, function (value2) {
step3 (value2, function (value3) {
step4 (value3, function (value4) {
// hacer algo con valor4
});
});
});
});
Este es en realidad el problema del flujo de control en Node.js. Hay muchas soluciones a este problema, como el uso de Async, EventProxy, etc. Sin embargo, el tema de este artículo es utilizar la promesa en la especificación CommonJS para resolver este problema.
¿Qué es la promesa?
Hay muchos tipos de especificaciones de promesa para CommonJS. Generalmente discutimos la especificación Promise/A+, que define el comportamiento básico de la promesa.
Una promesa es un objeto que generalmente representa una operación asincrónica que puede completarse en el futuro. Esta operación puede tener éxito o fallar, por lo que un objeto de promesa generalmente tiene 3 estados: pendiente, cumplido y rechazado. Representa la falla inacabada de finalización y operación exitosa, respectivamente. Una vez que el estado del objeto de la promesa cambia de pendiente a cumplido o rechazado, su estado no se puede cambiar nuevamente.
Un objeto de promesa generalmente tiene un método entonces, que nos permite operar el valor devuelto después del posible éxito en el futuro o el motivo de la falla. Este método entonces se ve así:
Promesa.
Es obvio que el método entonces acepta dos parámetros, que generalmente son dos funciones, una se usa para procesar el resultado después de que la operación es exitosa y el otro se usa para procesar la causa de la falla de la operación. Los primeros parámetros de estas dos funciones son el resultado después del éxito y la causa de la falla. Si el método entonces no es una función, entonces se ignorará este parámetro.
El valor de retorno del método entonces es un objeto prometedor, que nos permite encadenar la llamada para lograr el efecto de controlar el proceso. Aquí hay muchos detalles, como la transferencia de valor o el manejo de errores. La especificación de la promesa se define así:
El valor de retorno de la función Onfulled o OnRegected no es un objeto prometedor, entonces el valor se utilizará como el primer parámetro de Onfullilled en el siguiente método. Si el valor de retorno es un objeto prometedor, ¿cómo puede el valor de retorno del método entonces ser el objeto de promesa?
Si se lanza una excepción en la función onfullida o realizada, el estado del objeto prometedor devuelto del método entonces se convierte en rechazado. Si el objeto prometedor llama, el objeto de error se utilizará como el primer parámetro de la función OnRejed.
Si el estado de la promesa se cumple y la función onfullida no se proporciona en el método entonces, el estado de objeto de promesa devuelto por el método entonces se cumple y el resultado exitoso es el resultado de la promesa anterior, lo mismo es cierto para rechazar.
Para agregar, tanto onfulled como onrejected se ejecutan asincrónicamente.
Implementación de la especificación: Q
Lo anterior se trata de la especificación de la promesa, y lo que necesitamos es su implementación. Q es una biblioteca que tiene mejores especificaciones de implementación para Promise/A+.
En primer lugar, necesitamos crear un objeto prometedor. Las especificaciones para la creación del objeto prometedor son prometedor/b. No explicaré en detalle aquí, solo agregue el código.
La copia del código es la siguiente:
función (bandera) {
var diferir = q.defer ();
fs.ReadFile ("A.Txt", function (err, data) {
if (err) diferir.reject (err);
else diferir.resolve (datos);
});
return diferir.promise;
}
La mayoría de las implementaciones prometedoras son similares en la creación de promesas. Al crear un objeto Difer con atributo prometedor, si el valor se obtiene con éxito, se llama diferir.resolve (valor), si falla, se llama a los reject (razón) y finalmente devuelve el atributo prometedor de diferir. Este proceso puede entenderse como Llamar Difer.
Cuando se enfrenta a una serie de métodos asíncronos continuos, ¿cómo puede escribir un código hermoso usando prometía? Eche un vistazo al siguiente ejemplo.
La copia del código es la siguiente:
Promise0.Then (function (resultado) {
// Dosomething
resultado de retorno;
}). entonces (función (resultado) {
// Dosomething
Regreso promise1;
}). entonces (función (resultado) {
// Dosomething
}). Catch (function (ex) {
console.log (ex);
}). Finalmente (function () {
console.log ("final");
});
En el código anterior, el método entonces solo acepta OnfullInfelled, y el método de captura es en realidad entonces (NULL, OnRejed). De esta manera, siempre que una serie de métodos asincrónicos siempre devuelvan los valores con éxito, el código se extenderá hacia abajo en un estilo de cascada. Si alguno de los métodos asíncronos fallan o se produce una excepción, entonces, de acuerdo con la especificación de promesa de CommonJS, se ejecutará la función en la captura. Q también proporciona finalmente el método, que es fácil de entender literalmente, es decir, ya sea que resuelva o rechace, la función finalmente se ejecutará.
Se ve bien, el código es más mantenido y hermoso, entonces, ¿qué pasa si quieres concurrencia?
La copia del código es la siguiente:
Q.all ([Promes00, Promis1, Promis2]). Diftuera (Función (Val0, Val1, Val2) {
console.log (argumentos);
}). entonces (function () {
console.log ("hecho");
}). Catch (function (err) {
console.log (err);
});
Q también proporciona una API para la concurrencia, llamando a todos los métodos y aprobando una matriz de promesas puede continuar utilizando el estilo de cadena de entonces. También hay cosas buenas como Q.nfbind, etc. que pueden convertir la API nativa de Node.js en promesa de unificar el formato de código. Más API no se describirán en detalle aquí.
en conclusión
Este artículo presenta principalmente el uso de la promesa de resolver el problema de flujo de control de nodo.js, pero la promesa también se puede aplicar al front-end. EMCAScript6 ha proporcionado soporte de API nativo. Cabe señalar que la promesa no es la única solución, Async también es una buena opción y proporciona una API de control de concurrencia más amigable, pero creo que Promise tiene más ventajas al encapsular funciones con métodos asíncronos.
De acuerdo, eso es todo para este artículo, espero que sea útil para todos.