La mejor manera de trabajar con el DOM

Mientras escribía en Solid , tuve la oportunidad de estimar el número de intentos de optimizar el rendimiento en gráficos (puntos de referencia).

DOM es un desarrollo de cuello de botella front-end. Diferentes soluciones pueden conducir a resultados similares. Nuevas bibliotecas aparecen cada semana, incorporando lo mejor de las anteriores, para hacer la combinación perfecta. Después de un tiempo, mis ojos comienzan a escapar de tanta variedad de soluciones.

No me malentiendas. Me encanta ver que las nuevas ideas cobren vida, pero todas tienen fallas y, a veces, conllevan una pérdida de comodidad o productividad. Entiendo las consecuencias de tal decisión, pero quiero compartir mis observaciones.

¿Cuál es la forma más rápida de trabajar con DOM?

  • Dom virtual
  • Etiquetado Literales de plantilla
  • Observables de grano fino

Comparación


JS Frameworks Benchmark es el mejor proyecto de código abierto para comparar el rendimiento de los marcos de JavaScript UI. Es mejor ejecutar pruebas localmente en lugar de utilizar resultados oficiales. Los resultados pueden variar según la máquina. Como estoy probando en una máquina débil, el rendimiento disminuirá notablemente.

Adoptaré los mejores enfoques para representar un árbol DOM para ilustrar la redundancia de ciertas soluciones. Lo haré utilizando la capacidad de Solid para admitir diferentes opciones de representación para imponer costos a medida que cambian las variables y comparar esto con resultados similares de otros marcos. Echemos un vistazo a ellos.

Variedades de sólidos:

  • sólido : versión del marco con el configurador proxy ES2015 además de las funciones de seguimiento de cambios integradas en plantillas de nodo DOM clonadas. Esto se logra precompilando plantillas JSX (Código)
  • señales sólidas : esta versión es la misma que la anterior, pero se utilizan señales sin formato en lugar de proxies. Esto complica el uso de la biblioteca, pero al final obtenemos un paquete más pequeño y un mejor rendimiento (Código)
  • luz fija : esta versión no utiliza la precompilación JSX en tiempo de ejecución (Código)
  • solid-h : esta versión utiliza HyperScript para crear `document.createElement` sobre la marcha. El resto usa la misma implementación que Solid (Code)

Otras bibliotecas

  • domc — -, DOM DSL (domain specific language) HTML, index.html (Code)
  • surplus — JSX `document.createElement`. Solid (Code)
  • ivi — Inferno, DOM. HyperScript Helpers-esque (Code)
  • lit-html — , c . Tagged Template Literals DOM- (Code)
  • inferno es el más rápido de los clones React y una de las bibliotecas virtuales DOM más rápidas. Utiliza directivas JSX especiales para un mejor rendimiento (Código)

Es posible que algunos de sus marcos favoritos no estén aquí, pero esta lista muestra versiones optimizadas de todas las técnicas que verá en los marcos más populares. Puede verlo como un indicador para evaluar las capacidades máximas de su biblioteca. Si está interesado en comparar el rendimiento de los marcos populares, le recomiendo este cuadro.

A modo de comparación, me gustaría agregar Web Assembly. Desafortunadamente, al momento de escribir esto, los registros WASM eran una implementación vainilla sin abstracciones de alto nivel. (Más tarde agregaron wasm-bindgen al marco - aprox. Traductor)

resultados


HyperScript (infierno, ivi, sólido-h)


HyperScript muestra el marcado como una composición de funciones (como ho React.createElement). Por ejemplo:

h('div', {id: 'my-element'}, [
  h('span', 'Hello'),
  h('span', 'John')
])

Los marcos DOM virtuales tienen esta propiedad. Incluso si usan JSX u otros motores de plantillas DSL, bajo el capó todavía se convierten en métodos de representación elemento por elemento. Esto se usa para construir un árbol DOM virtual para cada ciclo de renderizado. Pero, como se muestra aquí, las funciones representadas se pueden usar para crear un gráfico de dependencia reactivo, como en el caso de Solid.



Como puede ver, las bibliotecas con un DOM virtual son mucho más rápidas. El sólido pierde rendimiento debido a la creación excesiva de un gráfico reactivo. Observe la diferencia en los puntos de referencia # 1, # 2, # 7, # 8, # 9.



El recuerdo es menos convincente. Inferno y esta versión de Solid muestran aproximadamente el mismo resultado. Mientras que ivi usa más memoria.
, Solid, , VDOM. Solid , DOM, DOM. Solid JSX DOM . , . Solid fine grained evaluation . - .

Los marcos de seguimiento de actualizaciones reactivas muestran mejores resultados al actualizar filas. Este gráfico explicaría la popularidad de VDOM en los últimos años. Baste decir que si usa HyperScript con esta actualización, entonces es mejor que cambie a DOM virtual.

Plantillas de cadenas (domc, lit-html, luz sólida)


Cada biblioteca aquí tiene algo en común. Se representan en base a plantillas de elementos de clonación, se ejecutan en tiempo de ejecución y no usan VDOM. Pero todavía tienen diferencias. DomC y lit-html usan una diferencia de arriba hacia abajo similar a Virtual DOM, mientras que Solid usa un gráfico reactivo. Lit-html divide las plantillas en partes. DomC y Solid compila la plantilla en rutas separadas en tiempo de ejecución y las actualiza.



Esta categoría tiene la gama más amplia de rendimiento. DomC es el más rápido, y lit-html es el más lento. Solid Lit está en el medio. DomC demuestra que la simplicidad del código conduce al mejor rendimiento.

DomC se hunde solo en la sección 4 porque calcula la diferencia de nodos, lo que se vuelve más complicado a medida que aumenta la profundidad. Es bastante rápido, pero debe validar los resultados en Big Data.

Solid Lit es más productivo que Solid HyperScript. La compilación instantánea en tiempo de ejecución elimina los inconvenientes de crear un gráfico reactivo, lo que permite que el marco se ponga al día con ivi, la biblioteca VDOM más rápida (consulte la tabla completa al final del artículo).



DomC mostró buenos resultados en el consumo de memoria. Esto sucedió debido a la clonación de los elementos de la plantilla. Es de destacar que la generación de código en tiempo de ejecución puede tener una sobrecarga de rendimiento mínima en comparación con la compilación en la etapa de construcción. Quizás esta es una comparación injusta para lit-html porque el marco no utiliza esta técnica. Pero es justo decir que lit-html o bibliotecas similares como hyperHTML o lighterHTML no son la mejor manera de implementar Literales de plantillas etiquetadas. Y puede lograr buenos resultados incluso en tiempo de ejecución sin VDOM.

JSX precompilado (sólido, señales sólidas, excedente)


Estas bibliotecas usan JSX, que se compila en un DOM o gráfico reactivo en la etapa de construcción. Las plantillas pueden ser cualquier cosa, pero JSX proporciona un árbol de sintaxis limpio que mejora la experiencia del desarrollador.



Este grupo tiene resultados similares, pero la diferencia es muy importante. Los tres utilizan la misma biblioteca para gestionar S.js estado . Con el ejemplo de Solid Signals, puede ver que las funciones de seguimiento con clonación de elementos de plantilla proporcionan un mayor rendimiento. La implementación estándar de Solid se sobrecarga con los Proxies ES2015, lo que empeora el resultado en todos los gráficos. Surplus utiliza `document.createElement`, que degrada el rendimiento en las pruebas en las que se crean las líneas 1, 2, 7 y 8.



El consumo de memoria tiene resultados similares. En este caso, los servidores proxy agregan más complejidad que los elementos de la plantilla de clonación.

La conclusión aquí es que los proxies degradan el rendimiento y más bibliotecas deberían clonar plantillas. Por otro lado, puede considerar una pequeña pérdida en el rendimiento debido a los poderes como una inversión. El ejemplo Solid tiene la menor cantidad de código entre otros ejemplos: solo 66 líneas, tiene un 13% menos de espacio no en blanco que Svelte, una biblioteca que se enorgullece de su minimalismo.

El mejor en su clase (domc, ivi, señales sólidas, vanillajs)


Ahora tomemos a los ganadores en cada categoría y compárelos con el ejemplo brutal, efectivo y escrito a mano en JavaScript vainilla. Cada implementación representa una de las soluciones de seguimiento de estado más populares. Incluso puede dibujar una analogía entre estas bibliotecas y los Tres Grandes: Sólido → Vue, DomC → Angular, ivi → Reaccionar. Obtendrá este resultado si elimina todo lo superfluo, excepto el renderizado, y se deshace del código de 60-200kb.



DomC y Solid están cerca en términos de rendimiento, ivi está significativamente por detrás, pero DomC, en general, es más rápido. Su complejidad en comparación con vanillaJS es notablemente menor, pero es menos efectiva con actualizaciones parciales. Solo este criterio no es indicativo. Cualquiera que piense que VDOM es lento o tiene complicaciones innecesarias debe verificar esto por su cuenta.

La mayoría de las bibliotecas nunca tendrán este tipo de rendimiento.



DomC también lidera el gráfico con memoria. El sólido de grano fino supera a VDOM ivi en términos de consumo de memoria.

Curiosamente, estas bibliotecas no son mucho peores que vanillaJS, independientemente del método. Todos son muy rápidos.

Tamaño del paquete


Finalmente, me gustaría tocar el tamaño del paquete. Muchas pruebas reales se centran solo en estas métricas. Sí, el tamaño del paquete es importante y tiene una correlación directa con el rendimiento, pero ¿cuál es la diferencia? Sospecho que la complejidad del código es más importante que el tamaño.



Conclusión


Como de costumbre, los resultados en tales gráficos nunca son completamente convincentes. El proceso en sí y las conclusiones que sacamos son importantes. En este caso, vemos que el DOM en sí mismo es un gran cuello de botella en lo que respecta al rendimiento. Tanto es así que no existe una técnica inequívoca para eludirlo.


Christoper Lambert como The Highlander

No, no es tan simple. Ni el DOM ni el VDOM son lentos. Pero creo que se valen el uno al otro. Admito que la retórica de VDOM Performance React me llevó a estos pensamientos. La ignorancia de las opiniones sobre este tema es enfurecedora.

La afirmación de que VDOM es lenta se debe a la falta de conciencia. Representar VDOM y calcular la diferencia de estado es una complicación en comparación con no hacerlo. ¿Pero es su ausencia escalable? ¿Y cómo hacer cambios de datos?

Veo que hay una excepción en cada regla. En general, la precompilación combinada con Fine-Grained en marcos reactivos es la solución más rápida. Pero DomC muestra un alto rendimiento sin él. Los métodos JS nativos, como la clonación de elementos de plantilla con Tagged Template Literals, pueden ser la mejor solución para implementar lit-html de grandes corporaciones (Google). Pero este es uno de los marcos más lentos de esta tabla y ni siquiera la mejor implementación de estas tecnologías. Se considera que Svelte es la biblioteca más rápida de la comunidad, pero ni siquiera podría competir estrechamente con las soluciones presentadas.

Si la programación reactiva gana, esto no significa que todas las bibliotecas reactivas sean rápidas o que las métricas signifiquen todo. A pesar de la profunda comparación en este artículo, creo que en realidad hay bibliotecas rápidas y más lentas. Incluso si encontramos súper tecnología, aún enfrentaremos sus limitaciones.

Resultados de prueba de todas las bibliotecas en una tabla:


All Articles