Cómo hacer programas de front-end web eficientes es un problema que inconscientemente consideraré cada vez que realice el desarrollo front-end. Hace unos años, los increíbles ingenieros front-end en Yahoo publicaron un libro sobre la mejora del rendimiento del front-end web, lo que causó una sensación en toda la industria de la tecnología de desarrollo web, lo que hace que la misteriosa optimización del front-end cuestione una repollo en la calle, y la optimización del fondo web se ha convertido en una pregunta simple que tanto los novatos como los grandes gigantes pueden responder. Cuando toda la industria sabe la respuesta al impactante secreto, la tecnología de optimización existente ya no puede producir un salto cualitativo para el sitio web que desarrolla. Para hacer el rendimiento del sitio web, desarrollamos mejor que los sitios web de otras personas, necesitamos pensar más profundamente y reservar mejores habilidades.
El sistema de eventos en JavaScript es el primer punto de avance que pienso. ¿Por qué es un sistema de eventos JavaScript? Todos sabemos que el front-end web contiene tres tecnologías: HTML, CSS y JavaScript. Está claro cómo se combinan HTML y CSS: etiquetas de estilo, clase, ID y HTML. No hay nada de qué hablar, pero ¿cómo JavaScript ingresa al medio entre HTML y CSS y deja que los tres se integren? Finalmente, descubrí que este punto de entrada es el sistema de eventos de JavaScript. No importa cuánto tiempo o complejo código JavaScript que escribamos, se refleja en última instancia en HTML y CSS a través del sistema de eventos. Por lo tanto, estaba pensando que, dado que el sistema de eventos es el punto de entrada para la integración de los tres, inevitablemente habrá una gran cantidad de operaciones de eventos en una página, especialmente en las páginas web cada vez más complejas de hoy. Sin estos eventos, el código JavaScript que escribimos cuidadosamente solo se puede usar en la biblioteca, y los héroes son inútiles. Dado que hay una gran cantidad de funciones de eventos en la página, ¿habrá problemas que afecten la eficiencia al escribir funciones de eventos como estamos acostumbrados? La respuesta que he estudiado es que es un problema de eficiencia real, y también es un problema de eficiencia grave.
Para aclarar mi respuesta, quiero explicar el sistema de eventos de JavaScript en detalle.
El sistema de eventos es el punto de entrada para la fusión de JavaScript, HTML y CSS. Este punto es como la función principal en Java. Toda la magia comienza aquí. Entonces, ¿cómo completa el navegador esta entrada? He estudiado tres maneras, son:
Método 1: Procesamiento de eventos HTML
El procesamiento de eventos HTML es escribir funciones de eventos directamente en la etiqueta HTML. Debido a que este método de escritura está estrechamente junto con la etiqueta HTML, se llama procesamiento de eventos HTML. Por ejemplo, el siguiente código:
La copia del código es la siguiente:
<input type = "botón" id = "btn" name = "btn" onClick = "alerta ('Haga clic en mí!')"/>
Si la función del evento de clic es complicado, escribir código como este definitivamente causará inconvenientes. Por lo tanto, a menudo escribimos la función afuera y en el cierre llame directamente al nombre de la función, por ejemplo:
La copia del código es la siguiente:
<input type = "botón" id = "btn" name = "btn" onClick = "btnclk ()"/>
función btnclk () {
alerta ("¡Haz clic en mí!");
}
El método de escritura anterior es un método de escritura muy hermoso, por lo que muchas personas lo usarán inconscientemente hoy en día, pero muchas personas pueden no saber que el último método de escritura en realidad no es tan fuerte como el método de escritura anterior. Este también es un problema que encontré al estudiar la tecnología de script de carga que no es de bloqueo no hace mucho tiempo, porque de acuerdo con el principio de optimización delantera, el código JavaScript a menudo se encuentra en la parte inferior de la página. Cuando la página está bloqueada por un script, la función mencionada en la etiqueta HTML puede no haber sido ejecutada todavía. En este momento, hacemos clic en el botón de página, y el resultado se informará "la función XXX es un error indefinido". En JavaScript, tales errores se verán capturados por intento y atrapar. Por lo tanto, para hacer que el código sea más robusto, tendremos las siguientes reescrituras:
La copia del código es la siguiente:
<input type = "Button" id = "btn" name = "btn" onClick = "try {btnclk ();} catch (e) {}"/>
Ver el código anterior no es algo que pueda describirse por una persona desagradable.
Método 2: Procesamiento de eventos de nivel DOM0
El procesamiento de eventos de nivel DOM0 es un procesamiento de eventos compatible con todos los navegadores de hoy. No hay problema de compatibilidad. Ver tal oración hará que todos los que hacen un front-end web emocionen. La regla para el procesamiento de eventos DOM0 es: cada elemento DOM tiene su propio atributo de procesamiento de eventos, que se le puede asignar una función, como el siguiente código:
La copia del código es la siguiente:
var btndom = document.getElementById ("btn");
btndom.onclick = function () {
alerta ("¡Haz clic en mí!");
}
Los atributos del evento manejados por los eventos de nivel DOM0 se definen en forma de "Nombre del evento en+", y todo el atributo está en letras minúsculas. Sabemos que el elemento DOM es un objeto JavaScript en el código JavaScript, por lo que es muy fácil entender el procesamiento de eventos de nivel DOM0 desde la perspectiva del objeto JavaScript, por ejemplo, el siguiente código:
La copia del código es la siguiente:
btndom.onclick = null;
Luego se cancela el evento de clic del botón.
Veamos el siguiente código:
La copia del código es la siguiente:
btndom.onclick = function () {
alerta ("¡Haz clic en mí!");
}
btndom.onclick = function () {
alerta ("¡Haga clic en ME1111!");
}
La siguiente función sobrescribirá la primera función.
Método 3: Procesamiento de eventos DOM2 y procesamiento de eventos de IE
El procesamiento de eventos DOM2 es una solución estandarizada de procesamiento de eventos, pero el navegador IE ha desarrollado un conjunto de funciones y funciones son similares al procesamiento de eventos DOM2, pero el código es diferente de eso.
Antes de explicar el método tres, debo agregar algunos conceptos, de lo contrario, no podré explicar la connotación del método tres.
El primer concepto es: Flujo de eventos
En el desarrollo de la página, a menudo encontramos esta situación. El intervalo de trabajo de una página puede representarse mediante un documento en JavaScript. Hay un div en la página. El DIV es equivalente a superponer el elemento del documento. Hay un elemento de botón en el div. El elemento del botón superpone el DIV, que también es equivalente a superponer el documento. Entonces, el problema es que, cuando hacemos clic en este botón, este comportamiento de clic en realidad no solo ocurre en el botón. Tanto el DIV como el documento se utilizan para operaciones de clics. Según Logic, estos tres elementos pueden activar eventos de clics. La transmisión del evento describe el concepto del escenario anterior. La transmisión del evento significa: el orden de los eventos recibidos de la página.
El segundo concepto: burbujas de eventos y captura de eventos
Las burbujas de eventos son la solución propuesta por Microsoft para resolver el problema del flujo de eventos, mientras que la captura de eventos es la solución de flujo de eventos propuesta por Netscape. Sus principios son los siguientes:
El evento burbujeante comienza con un DIV, seguido de un cuerpo, y finalmente un documento, y la captura del evento se invierte, primero un documento, seguido de un cuerpo y finalmente un elemento objetivo Div. En contraste, la solución de Microsoft es más humana y en línea con los hábitos operativos de las personas, la solución de Netscape es muy incómoda. Esta es la consecuencia de la guerra del navegador. Netscape es más lento y resuelve el problema del flujo de eventos sacrificando el código al que los usuarios están acostumbrados.
Microsoft ha diseñado un nuevo sistema de eventos en combinación con eventos de burbujas, que comúnmente se conoce como procesamiento de eventos IE en la industria. El método de procesamiento de eventos IE es el que se muestra en el siguiente código:
La copia del código es la siguiente:
var btndom = document.getElementById ("btn");
btndom.attachevent ("onClick", function () {
alerta ("¡Haz clic en mí!");
});
Agregue los eventos a través del método AttachmentEvent del elemento DOM en IE. En comparación con el procesamiento de eventos DOM0, el método de agregar eventos ha cambiado de atributos a métodos, por lo que cuando agregamos eventos, necesitamos pasar parámetros al método. El método AttachmentEvent recibe dos parámetros. El primer parámetro es el tipo de evento. El nombramiento del tipo de evento es el mismo que el nombramiento del evento en el procesamiento de eventos DOM0. El segundo parámetro es la función del evento. La ventaja de usar el método es que si estamos agregando un evento de clic al mismo elemento, como se muestra a continuación:
La copia del código es la siguiente:
btndom.attachevent ("onClick", function () {
alerta ("¡Haz clic en mí!");
});
btndom.attachevent ("onClick", function () {
alerta ("¡Haz clic en mí también!");
});
Ejecutarlo, ambos cuadros de diálogo aparecen normalmente, lo que nos permite agregar múltiples eventos de clic diferentes al elemento DOM. ¿Qué pasa si no queremos un evento? ¿Qué debemos hacer? Proporciono un método de desmontación para eliminar eventos. La lista de parámetros es la misma que la adjunta. Si queremos eliminar un evento de clic cierto, simplemente pase los mismos parámetros que el evento Agregar, como se muestra en el siguiente código:
La copia del código es la siguiente:
btndom.detachevent ("onClick", function () {
alerta ("¡Haz clic en mí también!");
});
Al ejecutarlo, las consecuencias son muy graves y estamos confundidos. El segundo clic no fue eliminado. ¿Qué está sucediendo? Mencioné anteriormente que eliminar eventos requiere parámetros de aprobación como agregar eventos. Sin embargo, en la función anónima de JavaScript, incluso si el código de las dos funciones anónimas es exactamente el mismo, JavaScript usará diferentes variables para almacenarlas internamente. Como resultado, el fenómeno que vemos no puede eliminar el evento de clic, por lo que nuestro código debe escribirse así:
La copia del código es la siguiente:
var ftn = function () {
alerta ("¡Haz clic en mí también!");
};
btndom.attachevent ("onclick", ftn);
btndom.detachevent ("onclick", ftn);
El método agregado y el método eliminado de esta manera apuntan al mismo objeto, por lo que el evento se eliminó con éxito. El escenario aquí nos dice que necesitamos tener el buen hábito de escribir eventos que debemos definir las operaciones de forma independiente y no usar las funciones anónimas como un hábito.
El siguiente es el procesamiento de eventos DOM2, su principio se muestra en la figura a continuación:
DOM2 es un evento estandarizado. Usando eventos DOM2, la entrega de eventos comienza desde el método de captura, es decir, desde el documento y luego hasta el cuerpo. El DIV es un punto intermediario. Cuando el evento llega al punto intermediario, el evento está en la etapa objetivo. Después de que el evento ingresa a la etapa objetivo, el evento comienza a burbujear y manejar, y finalmente el evento termina en el documento. (Estoy señalando documentar en este artículo, pero la situación real es que algunos navegadores comenzarán a capturar el evento y terminar la burbuja en la ventana. Sin embargo, creo que no importa cómo se establece el navegador en el desarrollo, está más orientado al desarrollo de la atención al documento, por lo que estoy usando el documento aquí). Las personas se utilizan para clasificar la etapa objetivo como parte de la burbuja, principalmente porque los eventos de burbujas se utilizan más ampliamente en el desarrollo.
El procesamiento de eventos DOM2 es muy difícil. Cuando se active cada evento, todos los elementos se atravesarán dos veces. En comparación con el evento IE, el rendimiento es mucho peor que el evento IE. Solo estoy burbujeando, así que solo necesito atravesar una vez. Sin embargo, menos transversal no significa que el sistema de eventos IE sea más eficiente. Apoyar dos sistemas de eventos al mismo tiempo traerá una mayor flexibilidad a nuestro desarrollo desde la perspectiva del desarrollo y el diseño. Desde esta perspectiva, los eventos DOM2 siguen siendo muy deseables. El código para el evento DOM2 es el siguiente:
La copia del código es la siguiente:
var btndom = document.getElementById ("btn");
btndom.addeventListener ("hacer clic", function () {
alerta ("¡Haz clic en mí!");
},FALSO);
var ftn = function () {
alerta ("¡Haz clic en mí también!");
};
btndom.addeventListener ("hacer clic", ftn, falso);
La adición de eventos en el procesamiento de eventos DOM2 utiliza AddEventListener, que recibe un parámetro más que el procesamiento de eventos IE. Los dos primeros significan lo mismo que los dos parámetros del método de procesamiento de eventos IE. La única diferencia es que el prefijo ON se elimina en el primer parámetro, y el tercer parámetro es un valor booleano. Si su valor es verdadero, el evento se procesará en el modo de captura, con el valor falso. El evento se procesa en burbujas. Con el tercer parámetro, podemos entender por qué el elemento del evento debe ejecutarse dos veces en el procesamiento de eventos DOM2. El propósito es ser compatible con los dos modelos de eventos. Sin embargo, tenga en cuenta aquí que no importa si elegimos capturar o burbujear, los dos transversales se llevarán a cabo para siempre. Si elegimos un método de procesamiento de eventos, entonces no se activará ninguna función de procesamiento de eventos en el otro proceso de procesamiento de eventos. Esto es lo mismo que el principio de inactivar el automóvil en equipo neutral. A través del diseño del método del evento DOM2, sabemos que los eventos DOM2 solo pueden ejecutar uno de los dos métodos de procesamiento de eventos en tiempo de ejecución. Es imposible que dos sistemas de transmisión de eventos provocen al mismo tiempo. Por lo tanto, aunque el elemento se atraviesa dos veces, la función del evento no se puede provocar dos veces. Tenga en cuenta que quiero decir que no se provocan dos veces, lo que se refiere a una función de evento. De hecho, podemos simular la situación en la que se ejecutan dos modelos de transmisión de eventos al mismo tiempo, como el siguiente código:
La copia del código es la siguiente:
btndom.addeventListener ("hacer clic", ftn, true);
btndom.addeventListener ("hacer clic", ftn, falso);
Pero esta forma de escribir es el procesamiento de eventos múltiples, que es equivalente a hacer clic en el botón dos veces.
DOM2 también proporciona una función para eliminar eventos. Esta función es RemoVentListener, escrita de la siguiente manera:
La copia del código es la siguiente:
btndom.removeEventListener ("hacer clic", ftn, falso);
Lo mismo es cierto para el evento IE, es decir, los parámetros deben ser consistentes con los parámetros que definen el evento. Sin embargo, cuando se usa RemoVentListener, el tercer parámetro no se pasa. El valor predeterminado es eliminar el evento de burbujas, porque el valor predeterminado es falso si no se pasa el tercer parámetro. Por ejemplo:
La copia del código es la siguiente:
btndom.addeventListener ("hacer clic", ftn, true);
btndom.removeEventListener ("hacer clic", ftn);
Ejecute y descubra que el evento no se eliminó con éxito.
Finalmente, quiero decir que el manejo de eventos DOM2 está bien compatible en IE9, incluido IE9 o superior, y el IE8 a continuación no admite eventos DOM2.
Comparemos los tres métodos de eventos a continuación, como sigue:
Comparación 1: Comparación de un método para un lado y los otros dos métodos
La forma de escribir el método uno es combinar HTML y JavaScript. Me tienes y yo te tengo. Profundizar este método para lograr un desarrollo mixto de HTML y JavaScript. En un término de software, es un acoplamiento de código. El acoplamiento del código no es bueno y es muy malo. Este es el nivel de un programador de novato, por lo que una vez que el método sea completamente derrotado, los otros dos métodos ganarán.
Comparación 2: Método 2 y Método 3
Los dos están escritos de la misma manera. A veces es realmente difícil decir quién es mejor o peor. Mirando el contenido anterior, encontramos que la mayor diferencia entre el Modo 2 y el Modo 3 es que solo hay un evento en un elemento DOM, y solo una vez, mientras que el Modo 3 puede permitir que un evento en un elemento DOM tenga múltiples funciones de manejo de eventos. En el procesamiento de eventos DOM2, el modo 3 también puede permitirnos controlar con precisión el método de flujo de eventos. Por lo tanto, la función del Modo 3 es más potente que el Modo 2, por lo que en comparación con el Modo 3, es ligeramente mejor.
El siguiente es el foco de este artículo: los problemas de rendimiento de los sistemas de eventos. Para resolver los problemas de rendimiento, uno debe encontrar un enfoque. Aquí pensaré en los problemas de rendimiento de los sistemas de eventos desde dos puntos de enfoque, a saber: reducir el número de recorridos y consumo de memoria.
En primer lugar, el número de recorridos. Ya sea para capturar transmisiones de eventos o transmisiones de eventos burbujeantes, recorrerán elementos, pero todos los recorridos comienzan desde la ventana o documento superior. Si el elemento DOM de la página tiene una relación profunda para padres e hijos, entonces cuantos más elementos transversales, más dañino será, como el procesamiento de eventos DOM2, mayor será el recorrido. ¿Cómo resolver el problema del recorrido de esta transmisión de eventos? Mi respuesta es no. Algunos amigos aquí pueden tener preguntas, ¿cómo es que no hay más? Hay un objeto de evento en el sistema de eventos, que es un evento. Este objeto tiene un método para evitar burbujas o capturar eventos. ¿Por qué digo que no hay nadie? La pregunta de este amigo tiene sentido, pero si queremos utilizar este método para reducir el recorrido, entonces nuestro código se ocupará de la relación entre los elementos de padre e hijo y la relación de elementos del abuelo. Si los elementos de la página están anidados mucho, esta es una tarea que no se puede completar, por lo que mi respuesta es que el problema del recorrido no se puede cambiar, y solo podemos adaptarnos a ella.
Parece que la reducción del recorrido no puede resolver el problema de rendimiento del sistema de eventos, por lo que ahora solo podemos considerar el consumo de memoria. A menudo escucho que la gente dice que C# es muy útil, pero es aún mejor para el desarrollo del front-end web. Podemos arrastrar directamente un botón a la página en el ide C#. Después de que el botón llega a la página, el código JavaScript agregará automáticamente un evento al botón. Por supuesto, la función del evento en el interior es una función vacía. Así que creo que podemos colocar 100 botones en la página de esta manera. Si un solo código no funciona, habrá un procesamiento de eventos de 100 botones, lo cual es muy conveniente. Finalmente, agregamos un evento de botón específico a uno de los botones para que la página se ejecute. ¿Es esta página eficiente? En JavaScript, cada función es un objeto, y cada objeto consume memoria, por lo que este código de función de evento 99 inútil debe consumir mucha memoria valiosa del navegador. Por supuesto, no haremos esto en el entorno de desarrollo real, pero en la era actual del desarrollo popular y de una sola página de Ajax es una locura y popular, hay tantos eventos en una página web, lo que significa que cada evento tiene una función de evento, pero cada operación solo activamos un evento. En este momento, otros eventos duermen mientras están acostados, lo que no juega ningún papel y consume memoria de la computadora.
Necesitamos una solución para cambiar esta situación, y de hecho existe tal solución en la realidad. Para describir claramente este plan, primero quiero agregar algún conocimiento de fondo. En la discusión del procesamiento de eventos DOM2, mencioné el concepto de objeto objetivo. Dejando de lado el método de procesamiento de eventos DOM2, también existe el concepto de objeto objetivo en el procesamiento de eventos de captura y el procesamiento de eventos de burbujas. El objeto objetivo es el elemento DOM de la operación específica del evento. Por ejemplo, el botón en la operación del botón de clic es el objeto de destino. No importa qué método de procesamiento de eventos, la función del evento contendrá un objeto de evento. El objeto del evento tiene un objetivo de atributo, el objetivo siempre apunta al objeto de destino, y el objeto de eventos tiene otro atributo, CurrentTarget, que apunta al elemento DOM que fluye al evento de captura o burbuja. De la descripción anterior, sabemos que si se trata de un evento de captura o un evento de burbujas, el flujo de eventos fluirá al documento. Si agregamos un evento de clic en el documento y el botón de la página no agrega un evento de clic, entonces hacemos clic en el botón y sabemos que el evento de clic en el documento se activará. Aquí hay un detalle que cuando se activa el evento de clic en el documento, el objetivo del objetivo del evento es el botón en lugar del documento, por lo que podemos escribir el código así:
La copia del código es la siguiente:
<input type = "botón" id = "btn" name = "btn" valor = "botón"/>
<a href = "#" id = "aa"> aa </a>
document.addeventListener ("hacer clic", function (evt) {
var Target = evt.target;
Switch (Target.id) {
Caso "BTN":
alerta ("botón");
romper;
Caso "AA":
alerta ("A");
romper;
}
},FALSO);
Ejecutándolo, descubrimos que el efecto es el mismo que el evento que escribimos el botón por separado. Pero sus beneficios son evidentes. Una función maneja la función de evento de toda la página, y ninguna función de evento es inactiva, lo cual es perfecto. Este plan también tiene un nombre profesional: delegación de eventos. El método delegado de JQuery se realiza de acuerdo con este principio. De hecho, la eficiencia de la delegación de eventos no solo se refleja en la reducción de las funciones del evento, sino que también reduce las operaciones transversales de DOM. Por ejemplo, en el ejemplo anterior, agregamos una función en el documento. El documento es el objeto de nivel superior en la página, y la eficiencia de leerlo es muy alta. Cuando se trata de eventos de objeto específicos, no usamos la operación DOM, sino que usamos el atributo de destino del objeto de evento. Todo esto solo se puede resumir en una oración: es realmente rápido, no hay razón para ser rápido.
La delegación de eventos también puede traernos un gran subproducto. Los amigos que han usado jQuery deberían haber usado el método en vivo. La característica del método en vivo es que puede agregar operaciones de eventos a elementos de página. Incluso si este elemento no existe en la página en la actualidad, puede agregar sus eventos. Después de comprender el mecanismo de delegación de eventos, el principio de vida es fácil de entender. De hecho, JQuery's Live se realiza a través de la delegación de eventos, y Live también es una forma eficiente de agregar evento.
Después de comprender la delegación de eventos, encontraremos que el método de enlace de JQuery es un método ineficiente. Debido a que utiliza el método de definición de evento original, debemos usar BIND con precaución. De hecho, los desarrolladores de jQuery también han notado este problema. La nueva versión de jQuery tiene un método ON. El método ON contiene todas las funciones de los métodos BIND, Live y Delegate. Así que sugiero que los amigos que han leído este artículo abandonen el método anterior de agregar eventos y usar las funciones para agregar eventos.
La delegación de eventos tiene otra ventaja. En el ejemplo de delegación de eventos en el artículo anterior, agregué eventos al documento. Aquí quiero hacer una comparación. En jQuery, estamos acostumbrados a poner la definición de eventos de elementos DOM en el método listo, como se muestra a continuación:
La copia del código es la siguiente:
$ (documento) .Ready (function () {
Xxx.bind ("hacer clic", function () {});
});
La función lista se ejecuta después de cargar el documento DOM de página. Primero se ejecuta que la función Onload. Esto tiene muchos beneficios por adelantado. Uno de los beneficios también es mejorar el rendimiento. La definición de evento como jQuery también es una práctica estándar. Creo que algunos amigos deben unir ciertos eventos fuera de Ready, y finalmente encontrar que el botón no será válido. Este escenario no válido a veces lleva un momento, y estará bien después de un tiempo. Por lo tanto, a menudo ignoramos el principio de este problema y no unimos eventos en la función lista. Esta operación es en realidad eventos vinculantes antes de que se cargue el DOM, y bajo este período de tiempo, en realidad nos vinculamos. , Es muy probable que no se hayan construido algunos elementos en la página, por lo que la unión del evento no será válida. Por lo tanto, el motivo de los eventos listos para definir es garantizar que todos los elementos de la página estén cargados para definir los eventos del elemento DOM después de que se carguen. Sin embargo, se pueden evitar problemas al usar delegados de eventos. Por ejemplo, eventos vinculantes a un documento, el documento representa la página completa, por lo que es el momento más temprano para cargarlo. Por lo tanto, es difícil lograr delegados de eventos en el documento, y también es difícil hacer que el navegador informe "Función XXX indefinida". Para resumir esta función: el código de delegado de eventos se puede ejecutar en cualquier etapa de la carga de la página, que proporcionará a los desarrolladores una mayor libertad para mejorar el rendimiento de la página web o mejorar los efectos de la página web.
Ok, este artículo ha sido escrito. Buenas noches.