Como sabrán, el entorno de ejecución del idioma JavaScript es "un solo hilo".
El llamado "hilo único" significa que una tarea solo se puede completar a la vez. Si hay múltiples tareas, debe hacer cola, completar la tarea anterior, ejecutar la siguiente tarea, y así sucesivamente.
La ventaja de este modelo es que es relativamente simple de implementar y el entorno de ejecución es relativamente simple; La desventaja es que mientras haya una tarea que lleva mucho tiempo, las tareas posteriores deben colocarse en cola, lo que retrasará la ejecución de todo el programa. Los navegadores comunes no responden (muerte falsa) a menudo porque un cierto código de JavaScript se ejecuta durante mucho tiempo (como un bucle muerto), lo que hace que toda la página esté atrapada en este lugar y no se puede ejecutar otras tareas.
Para resolver este problema, el lenguaje JavaScript divide el modo de ejecución de las tareas en dos tipos: sincrónico (sincrónico) y asíncrono (asíncrono).
"Modo sincrónico" es el patrón de la sección anterior. La última tarea espera que la tarea anterior finalice y luego se ejecute. La orden de ejecución del programa es consistente y sincrónica con el orden de disposición de las tareas; El "modo asíncrono" es completamente diferente. Cada tarea tiene una o más funciones de devolución de llamada (devoluciones de llamada). Después de que termine la tarea anterior, no es la siguiente tarea, pero la función de devolución de llamada se ejecuta. La última tarea se ejecuta sin esperar a que finalice la tarea anterior, por lo que la orden de ejecución del programa es inconsistente y asíncrona con el orden de disposición de las tareas.
El "modo async" es muy importante. En el lado del navegador, las operaciones a largo plazo deben ejecutarse asincrónicamente para evitar que el navegador pierda respuesta. El mejor ejemplo son las operaciones AJAX. En el lado del servidor, el "modo asíncrono" es incluso el único modo, porque el entorno de ejecución es de un solo hilo, si todas las solicitudes HTTP pueden ejecutarse sincrónicamente, el rendimiento del servidor disminuirá bruscamente y pronto perderá su respuesta.
Este artículo resume 4 métodos de programación de "modo asincrónico". Comprenderlos le permite escribir programas JavaScript con una estructura más razonable, un mejor rendimiento y un mantenimiento más conveniente.
1. Función de devolución de llamada
Este es el método más básico de programación asincrónica.
Suponga que hay dos funciones F1 y F2, esta última esperando el resultado de la ejecución del primero.
La copia del código es la siguiente:
f1 ();
f2 ();
Si F1 es una tarea que requiere mucho tiempo, puede considerar reescribir F1 y escribir F2 como la función de devolución de llamada de F1.
La copia del código es la siguiente:
función f1 (devolución de llamada) {
setTimeOut (function () {
// Código de tarea de F1
llamar de vuelta();
}, 1000);
}
El código de ejecución se vuelve así:
La copia del código es la siguiente:
F1 (F2);
De esta manera, convertimos las operaciones sincrónicas en operaciones asincrónicas. F1 no bloqueará la operación del programa, que es equivalente a ejecutar primero la lógica principal del programa y posponer la ejecución de la operación que consumen mucho tiempo.
La ventaja de las funciones de devolución de llamada es que son simples, fáciles de entender e implementar, y la desventaja es que no conducen a la lectura y mantenimiento del código. Están altamente acoplados (acoplamiento) entre las diversas partes, y el proceso será muy caótico, y cada tarea solo puede especificar una función de devolución de llamada.
2. Monitoreo de eventos
Otra idea es adoptar un modelo basado en eventos. La ejecución de una tarea no depende del orden del código, sino de si ocurre un evento.
Tomemos F1 y F2 como ejemplos. Primero, vincule un evento para F1 (el método de escritura jQuery utilizado aquí).
La copia del código es la siguiente:
f1.on ('hecho', f2);
La línea de código anterior significa que cuando el evento hecho ocurre en F1, F2 se ejecuta. Entonces, reescribe F1:
La copia del código es la siguiente:
función f1 () {
setTimeOut (function () {
// Código de tarea de F1
f1.rigger ('Done');
}, 1000);
}
F1.trigger ('hecho') significa que después de completar la ejecución, el evento hecho se activa de inmediato, comenzando a ejecutar F2.
La ventaja de este método es que es relativamente fácil de entender. Puede unir múltiples eventos, y cada evento puede especificar múltiples funciones de devolución de llamada, y puede ser "desacoplamiento", que es propicio para la modularización. La desventaja es que todo el programa se basará en eventos, y el proceso de operación quedará muy poco claro.
3. Publicar/suscribirse
El "evento" en la sección anterior puede entenderse completamente como una "señal".
Suponemos que hay un "centro de señal". Después de completar una tarea, se publica una señal en el centro de señal. Otras tareas pueden "suscribirse" la señal al centro de señal, para saber cuándo puede iniciar la ejecución. Esto se llama "Publicado Patrón de suscripción", también conocido como el "Patrón de Observador".
Hay muchas implementaciones de este modelo. El siguiente es el pequeño pub/sub de Ben Alman, que es un complemento para jQuery.
Primero, F2 se suscribe a la señal "Hecha" a la jQuery "Centro de señal".
La copia del código es la siguiente:
jQuery.subscribe ("Hecho", F2);
Entonces, F1 se reescribe de la siguiente manera:
La copia del código es la siguiente:
función f1 () {
setTimeOut (function () {
// Código de tarea de F1
jQuery.publish ("hecho");
}, 1000);
}
jQuery.publish ("hecho") significa que después de que se completa la ejecución de F1, se emite una señal "realizada" a la jQuery "Centro de señal", lo que desencadena la ejecución de F2.
Además, después de que se ejecuta F2, la cancelación de suscripción también se puede dejar de suscripción.
La copia del código es la siguiente:
jQuery.UnsubScribe ("hecho", f2);
La naturaleza de este método es similar a la "escucha de eventos", pero es significativamente mejor que el último. Debido a que podemos monitorear el funcionamiento del programa observando el "centro de mensajes" para comprender cuántas señales existen y cuántos suscriptores son para cada señal.
4. Promesas objeto
El objeto Promeses es una especificación propuesta por el grupo de trabajo CommonJS, con el propósito de proporcionar una interfaz unificada para la programación asincrónica.
En pocas palabras, su idea es que cada tarea asincrónica devuelve un objeto prometedor, que tiene un método entonces que permite especificar la función de devolución de llamada. Por ejemplo, la función de devolución de llamada F2 de F1 se puede escribir como:
La copia del código es la siguiente:
F1 (). Entonces (F2);
F1 debe reescribirse de la siguiente manera (la implementación de jQuery se usa aquí):
La copia del código es la siguiente:
función f1 () {
var dfd = $ .deferred ();
setTimeOut (function () {
// Código de tarea de F1
dfd.resolve ();
}, 500);
return dfd.promise;
}
La ventaja de escribir de esta manera es que la función de devolución de llamada se ha convertido en un método de escritura en cadena, y el flujo del programa se puede ver muy claramente, y hay un conjunto completo de métodos de apoyo que puede realizar muchas funciones poderosas.
Por ejemplo, especifique múltiples funciones de devolución de llamada:
La copia del código es la siguiente:
F1 (). Entonces (F2) .Then (F3);
Por ejemplo, especifique la función de devolución de llamada cuando ocurre un error:
La copia del código es la siguiente:
f1 (). Entonces (F2) .fail (F3);
Además, tiene una ventaja que ninguno de los tres métodos anteriores tiene: si se ha completado una tarea, agregue una función de devolución de llamada y la función de devolución de llamada se ejecutará de inmediato. Por lo tanto, no tiene que preocuparse por perderse un evento o señal. La desventaja de este método es que es relativamente difícil de escribir y comprender.