Optimización o cómo no dispararte en el pie

Buen dia a todos. Hoy quiero hablar contigo sobre la optimización. Qué es, por qué es necesario y, lo más importante, cómo asegurarse de que no duela dolorosamente en ese momento.


En primer lugar, entenderemos qué es la optimización en general y qué es la optimización en JS. Entonces, la optimización es la mejora de algo de acuerdo con alguna característica cuantitativa. JS identificó cuatro características cuantitativas por sí mismo:


La cantidad de código : generalmente se acepta que cuantas menos líneas de código se escriban, más productivas y mejores. Mi opinión es fundamentalmente diferente, porque al escribir una línea de código puede crear tal pérdida de memoria o ciclo perpetuo que el navegador simplemente muere.


La velocidad (rendimiento) es la llamada complejidad computacional, es decir, la cantidad de acciones que el analizador necesitará realizar para ejecutar la instrucción.


Velocidad de creación : no es ningún secreto que ahora casi ninguno de los proyectos puede funcionar sin constructores como Webpack o Gulp, por lo tanto, esta característica muestra la corrección de la configuración del creador de proyectos. Créame, cuando el servidor es un poco más inteligente que el molinillo de café, se vuelve importante.


Reutilización de código : esta característica muestra qué tan bien se construye la arquitectura para reutilizar funciones, componentes y módulos.
Considere cada una de las categorías con más detalle, analizaremos qué características incluye y de qué depende.


Volumen de código:

  • Doblaje Cuánto código del mismo tipo se escribió en diferentes lugares;
  • Comentarios Los comentarios en el código son buenos, pero me he encontrado con proyectos en los que había más comentarios que código;
  • Falta de unificación. Un buen ejemplo de tal problema son funciones similares, que tienen matices dependiendo de alguna propiedad.
  • La presencia de código muerto. Muy a menudo en los proyectos hay funciones de depuración o funciones que no se utilizan en absoluto.

Rendimiento:


  • Usando el mecanismo de almacenamiento en caché del navegador;
  • Optimización de código basada en aquellos entornos en los que se ejecutará;
  • La presencia de fugas de memoria;
  • Utilizando trabajadores web;
  • Usar referencias a elementos del árbol DOM;
  • Uso de variables globales;
  • La presencia de llamadas recursivas;
  • Simplificación de cálculos matemáticos.

Velocidad de construcción:


  • El número de dependencias externas;
  • Conversiones de código. Esto se refiere a la cantidad de fragmentos y su tamaño, conversiones CSS, pegado de archivos, optimización de gráficos y mucho más.

Reutilización de código:


  • Número de componentes;
  • Repetibilidad de componentes
  • Flexibilidad y personalización.

Como se dijo en artículos anteriores, para cambiar algo, debe determinar el punto de partida y determinar qué tan mal está todo. ¿Dónde comenzar un proceso tan voluminoso? Comience con lo más simple: acelere el tiempo de montaje y corte del exceso del proyecto. ¿Pregunta por qué vale la pena comenzar con esto? Debido al hecho de que dependen el uno del otro. Reducir la cantidad de código aumentará la velocidad de compilación de las compilaciones y, en consecuencia, aumentará su productividad.


La optimización del tiempo de compilación inevitablemente nos introduce al concepto de compilación "en frío": este es el proceso cuando un proyecto comienza desde cero y hasta el punto en que todas las dependencias se ven afectadas y el código se vuelve a compilar por completo. No confunda con Rebild: esto es reconstruir el código del cliente sin extraer dependencias externas y otras mallas.


Para aumentar la velocidad de construcción de la construcción ayudará:


  • Utilizando ensambladores modernos. Las tecnologías no se detienen, y si tiene el primer paquete web, cuando pase al cuarto verá un aumento agradable que ya no hace nada;
  • Deshacerse de todas las adicciones muertas. De vez en cuando, los desarrolladores, al tratar de encontrar la verdad en el fondo de la lata de ácido sulfúrico, se olvidan de limpiar después de sus propios experimentos. el paquete? Sí, no se incluirán en el ensamblaje en sí, pero el paquete se desinflará. La pregunta es, ¿por qué?
  • Divida el ensamblaje en varios perfiles según sus necesidades. Mínimo dos: prod y dev. Caso en cuestión: código de ofuscación. En prod, esto es obligatorio, ya que menos peso = carga más rápida, pero en ofuscación de desarrollo solo interfiere y gasta el tiempo de construcción en manipulaciones innecesarias;
  • Paralelización de pasos de ensamblaje individuales;
  • Usando clientes npm que pueden almacenar en caché.

Acelerar la reconstrucción y la construcción "en frío" requerirá eliminar comentarios innecesarios y partes muertas de código. Sin embargo, ¿qué hacer si tiene un gran proyecto y no es posible inspeccionarlo usted mismo? En tales casos, los analizadores de código vienen al rescate.


Personalmente, uso periódicamente SonarQube , no el mejor, pero flexible. Se le pueden enseñar las características del proyecto, si las hay. De vez en cuando hace cosas que al menos se paran, al menos caen, pero, como cualquier instrumento, debe ser capaz de usarlo y no olvidar ser escéptico sobre sus comentarios. A pesar de todas sus desventajas, se enfrenta a una explosión con la búsqueda de código muerto, comentarios, la presencia de copiar y pegar y cosas pequeñas, como la falta de una comparación estricta.


La diferencia fundamental entre SonarQube y ESlint / TSLint / Prettier y otros similares es que comprueba la calidad del código, aísla el doblaje, la complejidad del cálculo y también ofrece recomendaciones sobre los cambios necesarios. Los análogos simplemente verifican el código en busca de errores, sintaxis y formato.


En la práctica, me encontré con codacy , un buen servicio con una suscripción gratuita y de pago. Será útil si necesita verificar algo en el lateral, sin tener que desplegar esta 'cosechadora' en casa. Tiene una interfaz intuitiva, una indicación detallada de lo que está mal con el código y mucho más.


En este artículo no tocaré el tema de configurar la compilación, los fragmentos y el resto, porque todo depende de las necesidades del proyecto y del generador instalado. Quizás hablaré sobre esto en otros artículos.


Las manipulaciones realizadas ayudaron a acelerar el montaje: ganancias, pero ¿qué sigue? Dado que los analizadores pueden encontrar el doblaje de código, será útil colocarlo en módulos o componentes separados, aumentando así la reutilización del código.


Solo había una sección que no tocamos: la velocidad del código en sí. El mecanismo mismo de llevar a un sentido de productividad del mismo es llamado por toda la refactorización de palabras odiadas. Echemos un vistazo más de cerca a lo que vale la pena hacer al refactorizar y lo que no.


Regla de vida: si funciona, no lo toques, no debería guiarte en este proceso. La primera regla en TI: hacer una copia de seguridad, luego dirá gracias a usted mismo. En la parte delantera, antes de realizar cambios, realice pruebas para no perder funcionalidad en el futuro. Luego pregúntese: ¿cómo determinar los tiempos de carga y las pérdidas de memoria?


Esto ayudará a DevTool. No solo mostrará una pérdida de memoria, le indicará el tiempo de carga de la página, la reducción de la animación y, si tiene suerte, realizará una auditoría por usted, pero esto no es exacto. DevTools también tiene una buena característica, como limitar la velocidad de descarga, que le permitirá predecir la velocidad de carga de la página con Internet deficiente.


Pudimos identificar los problemas, ¡ahora vamos a resolverlos!


Para comenzar, reduciremos el tiempo de carga utilizando el mecanismo de almacenamiento en caché del navegador. El navegador puede almacenar todo en caché y, posteriormente, proporcionar al usuario datos del caché. Almacenamiento local y almacenamiento de sesiones que nadie te quitó. Le permiten almacenar algunos de los datos que ayudan a acelerar el SPA durante las descargas posteriores y reducir las solicitudes innecesarias del servidor.


Se considera necesario optimizar el código en función del entorno en el que se ejecutará, pero como muestra la práctica, consume mucho tiempo y esfuerzo, sin generar un crecimiento tangible. Propongo considerar esto solo como una recomendación.
Es naturalmente recomendable eliminar todas las pérdidas de memoria. No me enfocaré en esto, creo que todos saben cómo eliminarlos, y si no, simplemente búscalo en Google.


Otro de nuestros asistentes es un trabajador web. Los trabajadores web son hilos propiedad del navegador que se pueden usar para ejecutar código JS sin bloquear el bucle de eventos. Los trabajadores web pueden realizar tareas computacionalmente pesadas y largas sin bloquear el flujo de la interfaz de usuario. De hecho, cuando se usan, los cálculos se realizan en paralelo. Ante nosotros hay un verdadero subproceso múltiple. Hay tres tipos de trabajadores web:


  1. Trabajadores dedicados: el proceso principal crea instancias de trabajadores web dedicados. Solo el proceso en sí mismo puede intercambiar datos con ellos.
  2. Trabajadores compartidos (Trabajadores compartidos): el acceso a un trabajador compartido se puede obtener mediante cualquier proceso que tenga la misma fuente que el trabajador (por ejemplo, diferentes pestañas del navegador, iframe y otros trabajadores compartidos).
  3. Los trabajadores de servicio son trabajadores impulsados ​​por eventos registrados utilizando su fuente y ruta. Pueden controlar la página web a la que están vinculados interceptando y modificando comandos de navegación y solicitudes de recursos, y almacenando datos en caché que pueden controlarse con mucha precisión. Todo esto nos brinda excelentes herramientas para controlar el comportamiento de la aplicación en una situación determinada (por ejemplo, cuando la red no está disponible).

Cómo trabajar con ellos se puede encontrar fácilmente en Internet.


De alguna manera descubrimos los enfoques y los problemas de terceros, ahora propongo hablar sobre el código en sí.


En primer lugar, trate de deshacerse de las llamadas directas al árbol DOM, ya que esta es una operación que requiere mucho tiempo. Imaginemos que está constantemente manipulando algún tipo de objeto en su código. En lugar de trabajar con este objeto por referencia, constantemente extrae el árbol DOM para buscar este elemento y trabajar con él, e implementamos el patrón de almacenamiento en caché en el código.


El segundo paso es deshacerse de las variables globales. ES6 nos dio una invención maravillosa de la humanidad llamada variables de bloque (en términos simples, declaraciones de variables de var a let y const ).


Y finalmente, lo más delicioso. Aquí, desafortunadamente, no todos tienen la experiencia suficiente para entender los matices. Estoy en contra del uso de funciones recursivas. Sí, reducen la cantidad de código escrito, pero no puede funcionar sin problemas: a menudo, estas funciones recursivas no tienen condiciones de salida, simplemente se olvidan de ellas. Como en el adagio "puedes romper un dedo con un martillo, pero esto no es un problema de martillo, sino un dueño del dedo" o una broma sobre gatos: las funciones recursivas no son malas, debes poder cocinarlas.


A pesar de todo el poder de las aplicaciones front-end modernas, no debe olvidarse de lo básico. Un claro ejemplo de desperdicio e irracionalidad es la adición de nuevos elementos al comienzo de la matriz. Quién sabe, él entendió, y el que no, ahora lo diré. Todos saben que los elementos de matriz tienen su propio índice, y cuando vamos a agregar un nuevo elemento de matriz a su comienzo, la secuencia de acciones será la siguiente:


  1. Definición de longitud de matriz
  2. Numeración de cada elemento.
  3. Desplazamiento de cada elemento de matriz
  4. Insertar un nuevo elemento en una matriz
  5. Reindexar elementos de la matriz.

Resumen:


Es hora de redondear, y para aquellos que se sienten cómodos con el formato de los memos, mantenga una lista de pasos gracias a los cuales puede comprender en qué etapa de optimización se encuentra ahora y qué hacer a continuación:


  1. Determinamos cuánto está todo bien / mal, eliminamos las métricas.
  2. Eliminamos todo lo innecesario: dependencias no utilizadas, código muerto, comentarios innecesarios.
  3. Personalizamos y aceleramos el tiempo de montaje, configuramos diferentes perfiles para los contornos.
  4. Analizamos el código y decidimos qué partes optimizaremos y reescribiremos.
  5. Estamos escribiendo pruebas para evitar la pérdida de funcionalidad.
  6. Comenzamos la refactorización, nos deshacemos de las variables globales, las pérdidas de memoria, el código de doblaje y otra basura, y no nos olvidamos del almacenamiento en caché.
  7. Simplificamos la complejidad de los cálculos y llevamos todo lo posible al trabajador web.

Todo no es tan complicado como parece a primera vista. Tu secuencia probablemente será diferente a la mía, aunque solo sea porque tienes tu propia cabeza sobre tus hombros. Agregará nuevos elementos o, por el contrario, reducirá su número, pero la base de la lista será similar. Describí específicamente la división para que esta actividad se pueda ejecutar en paralelo con el trabajo principal. A menudo, el cliente no está listo para pagar el reproceso, ¿está de acuerdo?


Y finalmente


Creo en ti y que tendrás éxito. ¿Crees que soy ingenuo? Supongo que se sorprenderá, pero desde que encontró este artículo, léalo hasta el final, significa que (tengo buenas noticias para usted) tiene cerebro y está tratando de desarrollarlos. ¡Le deseo éxito en una tarea tan difícil como optimizar el frente!

Source: https://habr.com/ru/post/469127/


All Articles