Actualmente, una gran cantidad de operaciones asincrónicas están involucradas en la demanda, y las páginas reales están cada vez más inclinadas a aplicaciones de una sola página. En el futuro, puede usar la columna vertebral, angular, knockout y otros marcos, pero el problema de la programación asíncrona es el primer problema que se enfrenta. Con el aumento de los nodos, la programación asincrónica se ha convertido en un tema muy candente. Después de un período de aprendizaje y práctica, se resumen algunos detalles de la programación asincrónica.
1. Clasificación de programación asincrónica
Los métodos para resolver el problema asincrónico generalmente incluyen: devolución de llamada directa, pub/submodo (modo de evento), biblioteca de control de biblioteca asíncrona (como async, cuándo), promesa, generador, etc.
1.1 Función de devolución de llamada
Las funciones de devolución de llamada se usan comúnmente para resolver soluciones asincrónicas, a menudo expuestas y utilizadas, fáciles de entender y muy fáciles de implementar en bibliotecas o funciones. Este también es un método que las personas usan a menudo cuando usan programación asincrónica.
Sin embargo, el método de función de devolución de llamada tiene los siguientes problemas:
1. Se puede formar una pirámide anidada del mal, y el código no es fácil de leer;
2. Solo una función de devolución de llamada puede ser correspondiente, lo que se convierte en un límite en muchos escenarios.
1.2 PUB/SUB MODE (evento)
Este patrón también se llama modo de evento, que es la eventización de las funciones de devolución de llamada y es muy común en las bibliotecas de clase como JQuery.
El modo de suscriptor de publicación de eventos en sí no tiene el problema de las llamadas sincrónicas y asincrónicas, pero en el nodo, las llamadas emits se activan en su mayoría asincrónicamente con el bucle de eventos. Este modo a menudo se usa para desacoplar la lógica comercial. Los editores de eventos no necesitan prestar atención a la función de devolución de llamada registrada, ni necesitan prestar atención a la cantidad de funciones de devolución de llamada. Los datos se pueden transmitir de manera flexible a través de mensajes.
Los beneficios de este patrón son: 1. fácil de entender; 2. Ya no se limita a una función de devolución de llamada.
Cuando se trata de cosas malas: 1. Necesitas usar la biblioteca de clases; 2. El orden de los eventos y las funciones de devolución de llamada es muy importante
La copia del código es la siguiente:
var img = document.QuerySelect (#ID);
img.addeventListener ('load', function () {
// La imagen está cargada
......
});
img.addeventListener ('error', function () {
// algo salió mal
......
});
Hay dos problemas con el código anterior:
a. IMG realmente se ha cargado, y la función de devolución de llamada de carga está vinculada en este momento. Como resultado, la devolución de llamada no se ejecutará, pero aún espera ejecutar la función de devolución de llamada correspondiente.
La copia del código es la siguiente:
var img = document.QuerySelect (#ID);
función load () {
...
}
if (img.complete) {
carga();
} demás {
img.addeventListener ('cargar', carga);
}
img.addeventListener ('error', function () {
// algo salió mal
......
});
b. No se puede manejar bien las excepciones
Conclusión: El mecanismo del evento es el más adecuado para tratar con eventos repetidos en el mismo objeto, y no es necesario considerar el evento antes de que la función de devolución de llamada esté vinculada.
1.3 Biblioteca de control asíncrono
Las bibliotecas asíncronas actuales incluyen principalmente Q, When.js, Win.js, RSVP.JS, etc.
La característica de estas bibliotecas es que el código es lineal y se puede escribir de arriba a abajo, en línea con los hábitos naturales.
Las cosas malas también son diferentes en los estilos, que son inconvenientes de leer y aumentar los costos de aprendizaje.
1.4 Promesa
La promesa se traduce al chino como una promesa. Personalmente, después de la finalización de manera asincrónica, dará un resultado externo (éxito o fracaso) y prometirá que el resultado ya no cambiará. En otras palabras, Promise refleja el valor final del resultado de retorno de una operación (una promesa representa el valor eventual devuelto desde la finalización única de una operación). En la actualidad, la promesa se ha introducido en la especificación ES6, y los navegadores avanzados como Chrome y Firefox han implementado este método nativo internamente, lo cual es bastante conveniente de usar.
Las siguientes son las características de la promesa desde los siguientes aspectos:
1.4.1 Estado
Contiene tres estados: pendiente, realizado y rechazado. Los tres estados solo pueden someterse a dos transiciones (de pendiente ---> cumplidos, pendientes-> rechazados), y la transición del estado solo puede ocurrir una vez.
1.4.2 entonces método
El método entonces se usa para especificar la función de devolución de llamada después de completar el evento asíncrono.
Se puede decir que este método es el método de promesa del alma, que hace que la promesa llena de magia. Hay varias manifestaciones específicas de la siguiente manera:
a) Entonces el método devuelve prometía. Esto permite operaciones en serie de múltiples operaciones asincrónicas.
Con respecto al círculo amarillo 1 en la figura anterior, el procesamiento del valor es una parte más complicada de la promesa. El procesamiento del valor se divide en dos situaciones: objeto prometedor y objeto no promocional.
Cuando el valor no es un tipo de promesa, solo use el valor como el valor del parámetro de la resolución de la segunda promesa; Cuando se trata de un tipo de promesa, el valor está completamente determinados por el valor. Se puede considerar que Promsie2 es un títere de valor, y Promis2 es solo un puente que conecta diferente asíncrono.
La copia del código es la siguiente:
Promise.prototype.then = function (onFullIlfilled, OnRejed) {
devolver nuevo promesa (function (resolve, rechazar) {// La promesa aquí está marcada como promesa2
manejar({
Onfullado: Onfulled,
onrejected: onrejected,
Resolve: Resolve,
rechazar: rechazar
})
});
}
Function Handle (diferido) {
var maneTn;
if (state === 'Fulfilled') {
maneRefn = diferido. Confullido;
} else if (state === 'rechazado') {
manefn = diferido.onrejed;
}
var retir = manefn (valor);
diferido.resolve (ret); // Tenga en cuenta que la resolución en este momento es la resolución de la promesa2
}
function resolve (val) {
if (val && typeof val.then === 'function') {
val.Then (resolución); // Si Val es un objeto prometedor o un objeto de promesa de clase, el estado de promesa2 está completamente determinado por Val
devolver;
}
if (llamado) {// La devolución de llamada es la función de devolución de llamada especificada
devolución de llamada (val);
}
}
b) Se implementa la conversión entre múltiples bibliotecas asincrónicas diferentes.
Hay un objeto llamado entonces en asíncrono, que se refiere a un objeto con el método entonces. Mientras un objeto de objeto tenga el método entonces, se puede convertir, por ejemplo:
La copia del código es la siguiente:
var diferido = $ ('aa.ajax'); // !! diferido.then === Verdadero
var p = promet.resolve (diferido);
P.THEN (......)
1.4.3 Promesa CommonJS/A Especificación
Actualmente, existen especificaciones Promise/A y Promise/A+ para las especificaciones con respecto a la promesa, que muestra que la implementación de la promesa es bastante complicada.
La copia del código es la siguiente:
Entonces (FulfilledHandler, RechazlyHandler, Progresshandler)
1.4.4 Notas
La función de devolución de llamada en una promesa comparte el valor. En el procesamiento de resultados, el valor se pasa como un parámetro a la función de devolución de llamada correspondiente. Si el valor es un objeto, tenga cuidado de no modificar fácilmente el valor.
La copia del código es la siguiente:
var p = promet.resolve ({x: 1});
p.then (función (val) {
console.log ('Primera devolución de llamada:'+val.x ++);
});
p.then (función (val) {
console.log ('Segunda devolución de llamada:' + val.x)
})
// Primera devolución de llamada: 1
// Segunda devolución de llamada: 2
1.5 generador
Todos los métodos anteriores se basan en la función de devolución de llamada para completar las operaciones asincrónicas, y no son más que encapsular la función de devolución de llamada. ES6 propone generador, que agrega formas de resolver operaciones asíncronas y ya no se completa en función de las funciones de devolución de llamada.
La característica más importante del generador es que puede detener y reiniciar funciones, lo que es muy propicio para resolver operaciones asincrónicas. La combinación de la pausa del generador con el manejo de excepciones de Promise puede resolver el problema de programación asincrónico de manera más elegante. Referencia de implementación específica: Kyle Simpson
2. Problemas con la programación asincrónica
2.1 Manejo de excepciones
a) Los eventos asincrónicos incluyen dos enlaces: emisión de solicitudes asincrónicas y resultados de procesamiento. Estos dos enlaces están conectados a través de bucles de eventos. Luego, cuando intente Catch para realizar la captura de excepciones, debe capturarla.
La copia del código es la siguiente:
intentar {
Asyncevent (devolución de llamada);
} catch (err) {
......
}
El código anterior no puede captar la excepción en la devolución de llamada y solo puede obtener la excepción en el proceso de solicitud. Esto tiene problemas: si la emisión de la solicitud y el procesamiento de la solicitud son completados por dos personas, ¿hay problemas al manejar excepciones?
b) Promise implementa la entrega de excepciones, lo que brinda algunos beneficios para garantizar que el código no esté bloqueado en proyectos reales. Sin embargo, si hay muchos eventos asincrónicos, no es fácil descubrir qué evento asíncrono produce una excepción.
La copia del código es la siguiente:
// Descripción de la escena: Mostrar información de alarma de precio en CRM, incluida la información competitiva. Sin embargo, lleva mucho tiempo obtener la información competitiva. Para evitar una consulta lenta, el backend divide un registro en dos piezas para obtenerlo por separado.
// Paso 1: obtener información de alarma de precio, además de la información de la competencia
function getPriceceAmarmData () {
devolver nuevo promesa (function (resolve) {
Y.io (url, {
Método: 'Get',
Datos: parámetros,
ON: function () {
éxito: function (id, data) {
resolución (alarmData);
}
}
});
});
}
// Después de obtener la información de la alarma, vaya a obtener la información de la competencia
getPriceAlarmData (). Entonces (función (datos) {
// Renderización de datos, además de información competitiva
render (datos);
devolver nuevo promesa (function (resolve) {
Y.io (url, {
Método: 'Get',
Datos: {alarmList: data},
ON: function () {
éxito: function (id, compdata) {
resolución (compData);
}
}
});
});
}) // Después de obtener todos los datos, reproduciendo la información de la competencia
.Then (función (datos) {
// Renderizar la información de licitación
Render (datos)
}, function (err) {
// Manejo de excepciones
console.log (err);
});
El código anterior se puede convertir a lo siguiente:
La copia del código es la siguiente:
intentar{
// Obtener información de alarma que no sea competencia
var alarmData = alarmDataExceptComPare ();
render (alarmData);
// Consulta de información de competencia basada en información de alarma
var comparandoata = getCompareInfo (alarmaData);
render (comparadoata);
} catch (err) {
console.log (err.message);
}
En el ejemplo anterior, la excepción se maneja al final, de modo que cuando ocurre una excepción en un determinado enlace, no podemos saber exactamente qué evento se genera.
2.2 JQuery.
Las operaciones asíncronas también se implementan en jQuery, pero no cumplen con las especificaciones prometedor/a+ en la implementación, y se reflejan principalmente en los siguientes aspectos:
a. Número de parámetros: la promesa estándar solo puede aceptar un parámetro, mientras que jQuery puede pasar múltiples parámetros
La copia del código es la siguiente:
función asyncinjquery () {
var d = new $ .deferred ();
setTimeOut (function () {
d.Resolve (1, 2);
}, 100);
return d.promise ()
}
asyncinjquery (). entonces (función (val1, val2) {
console.log ('salida:', val1, val2);
});
// Salida: 1 2
b. Manejo de excepciones en el procesamiento de resultados
La copia del código es la siguiente:
función asyncinpromise () {
devolver nuevo promesa (function (resolve) {
setTimeOut (function () {
var jsonstr = '{"nombre": "mt}';
resolución (jsonstr);
}, 100);
});
}
asyncinpromise (). entonces (función (val) {
var d = json.parse (val);
console.log (d.name);
}). Entonces (nulo, function (err) {
console.log ('Show Error:' + err.message);
});
// Mostrar error: final de entrada inesperado
función asyncinjquery () {
var d = new $ .deferred ();
setTimeOut (function () {
var jsonstr = '{"nombre": "mt}';
d.Resolve (JSonstr);
}, 100);
return d.promise ()
}
asyncinjquery (). entonces (función (val) {
var d = json.parse (val);
console.log (d.name);
}). entonces (función (v) {
console.log ('éxito:', v.name);
}, function (err) {
console.log ('Show Error:' + err.message);
});
// SyntaxError de sintaxis: final de entrada inesperado
Se puede ver a partir de esto que la promesa procesa el resultado de la función de devolución de llamada, que puede capturar excepciones durante la ejecución de la función de devolución de llamada, pero jQuery.defered no puede.