¿Por qué "element.innerHTML+=" es un código incorrecto?

Resuelto ajax333221 asked hace 12 años • 9 respuestas

Me han dicho que no agregue cosas element.innerHTML += ...de esta manera:

var str = "<div>hello world</div>";
var elm = document.getElementById("targetID");

elm.innerHTML += str; //not a good idea?

¿Qué tiene de malo?, ¿qué otras alternativas tengo?

ajax333221 avatar Jul 17 '12 09:07 ajax333221
Aceptado

Cada vez que innerHTMLse configura, se debe analizar el HTML, construir un DOM e insertarlo en el documento. Esto lleva tiempo.

Por ejemplo, si elm.innerHTMLtiene miles de divs, tablas, listas, imágenes, etc., la llamada .innerHTML += ...hará que el analizador vuelva a analizar todo eso nuevamente. Esto también podría romper las referencias a elementos DOM ya construidos y provocar otro caos. En realidad, todo lo que desea hacer es agregar un elemento nuevo al final.

Es mejor simplemente llamar appendChild:

var newElement = document.createElement('div');
newElement.innerHTML = '<div>Hello World!</div>';
elm.appendChild(newElement);​​​​​​​​​​​​​​​​

De esta manera, el contenido existente de elmno se vuelve a analizar.

NOTA: Es posible que [algunos] navegadores sean lo suficientemente inteligentes como para optimizar el +=operador y no volver a analizar los contenidos existentes. No he investigado esto.

Mike Christensen avatar Jul 17 '2012 02:07 Mike Christensen

Sí, elm.innerHTML += str;es una muy mala idea.
Úselo elm.insertAdjacentHTML( 'beforeend', str )como la alternativa perfecta.

La típica respuesta "el navegador tiene que reconstruir el DOM" realmente no hace justicia a la pregunta:

  1. Primero, el navegador debe revisar cada elemento de elm, cada una de sus propiedades y todos sus textos, comentarios y nodos de proceso, y escapar de ellos para crear una cadena.

  2. Luego tienes una cadena larga, a la que agregas. Este paso está bien.

  3. En tercer lugar, cuando configuras internalHTML, el navegador tiene que eliminar todos los elementos, propiedades y nodos por los que acaba de pasar.

  4. Luego analiza la cadena, la construye a partir de todos los elementos, propiedades y nodos que acaba de destruir, para crear un nuevo fragmento DOM que es prácticamente idéntico.

  5. Finalmente, adjunta los nuevos nodos y el navegador tiene que diseñar todo. Esto puede evitarse (consulte la alternativa a continuación), pero incluso si los nodos agregados requieren un diseño, los nodos antiguos tendrían sus propiedades de diseño almacenadas en caché en lugar de volver a calcularse desde cero.

  6. ¡Pero aún no ha terminado! El navegador también tiene que reciclar nodos antiguos escaneando todas las variables de JavaScript.

Problemas:

  • Es posible que HTML no refleje algunas propiedades; por ejemplo, el valor actual de <input>se perderá y se restablecerá al valor inicial en HTML.

  • Si tiene controladores de eventos en los nodos antiguos, se destruirán y deberá volver a conectarlos todos.

  • Si su código js hace referencia a nodos antiguos, no se destruirán, sino que quedarán huérfanos. Pertenecen al documento pero ya no están en el árbol DOM. Cuando su código acceda a ellos, es posible que no suceda nada o que se produzca un error.

  • Ambos problemas significan que no es compatible con los complementos js: los complementos pueden adjuntar controladores o mantener referencias a nodos antiguos y provocar una pérdida de memoria.

  • Si adquiere el hábito de manipular DOM con InnerHTML, puede cambiar propiedades accidentalmente o hacer otras cosas que no deseaba.

  • Cuantos más nodos tenga, más ineficiente será y más energía tendrá la batería para nada.

En resumen, es ineficiente, propenso a errores, simplemente es vago y desinformado.


La mejor alternativa esElement.insertAdjacentHTML que no he visto otras respuestas mencionar:

elm.insertAdjacentHTML( 'beforeend', str )

Casi el mismo código, sin los problemas de InnerHTML. Sin reconstrucción, sin pérdida de controlador, sin reinicio de entrada, menos fragmentación de memoria, sin malos hábitos, sin creaciones y asignaciones manuales de elementos.

Le permite inyectar cadenas html en elementos en una línea, incluidas propiedades, e incluso le permite inyectar elementos compuestos y múltiples. Su velocidad está optimizada : en la prueba de Mozilla es 150 veces más rápida.

En caso de que alguien le diga que no es compatible con varios navegadores, es tan útil que es el estándar HTML5 y está disponible en todos los navegadores .

No vuelvas a escribir nunca elm.innerHTML+=más.

Sheepy avatar Nov 30 '2015 09:11 Sheepy