Cuando innerHTML no es lo suficientemente rápido

Esta publicación no trata sobre los pros y los contras de innerHTML frente a los métodos DOM del W3C. Eso ha sido triturado y repetido en otros lugares. En cambio, mostraré cómo puedes combinar el uso de innerHTML y métodos DOM para hacer que su código sea potencialmente cientos de veces más rápido que innerHTML por sí solo, cuando se trabaja con un gran número de elementos.

En algunos navegadores (sobre todo Firefox), aunque innerHTML es generalmente mucho más rápido que los métodos DOM, gasta una cantidad desproporcionada de tiempo limpiando los elementos existentes frente a la creación de nuevos. Sabiendo esto, podemos combinar la velocidad de destrucción de elementos mediante la eliminación de su padre mediante los métodos DOM estándar con la creación de nuevos elementos mediante innerHTML . (Esta técnica es algo que descubrí durante el desarrollo de RegexPal, y es una de sus dos principales optimizaciones de rendimiento. La otra es la generación de marcado de una sola vez para resaltar coincidencias, lo que evita la necesidad de repetir las coincidencias o hacer referencia a ellas individualmente).

El código:

function replaceHtml(el, html) {
	var oldEl = typeof el === "string" ? document.getElementById(el) : el;
	/*@cc_on // Pure innerHTML is slightly faster in IE
		oldEl.innerHTML = html;
		return oldEl;
	@*/
	var newEl = oldEl.cloneNode(false);
	newEl.innerHTML = html;
	oldEl.parentNode.replaceChild(newEl, oldEl);
	/* Since we just removed the old element from the DOM, return a reference
	to the new element, which can be used to restore variable references. */
	return newEl;
};

Puede usar lo anterior como el = replaceHtml(el, newHtml) en lugar de el.innerHTML = newHtml .

innerHTML ya es bastante rápido... ¿realmente está justificado?

Eso depende de cuántos elementos estés sobrescribiendo. En RegexPal, cada evento keydown desencadena potencialmente la destrucción y creación de miles de elementos (para que la sintaxis y el resaltado de coincidencias funcionen). En tales casos, el enfoque anterior tiene un enorme impacto positivo. Incluso algo tan simple como el.innerHTML += str o el.innerHTML = "" podría ser un desastre de rendimiento si el elemento que está actualizando tiene algunos miles de elementos secundarios.

Creé una página que te permite probar fácilmente la diferencia de rendimiento de innerHTML y mi replaceHtml funcionan con varios números de elementos. Asegúrese de probarlo en algunos navegadores para comparar. Los siguientes son un par de ejemplos de resultados típicos de Firefox 2.0.0.6 en mi sistema:

1000 elements...
innerHTML (destroy only): 156ms
innerHTML (create only): 15ms
innerHTML (destroy & create): 172ms
replaceHtml (destroy only): 0ms (faster)
replaceHtml (create only): 15ms (~ same speed)
replaceHtml (destroy & create): 15ms (11.5x faster)

15000 elements...
innerHTML (destroy only): 14703ms
innerHTML (create only): 250ms
innerHTML (destroy & create): 14922ms
replaceHtml (destroy only): 31ms (474.3x faster)
replaceHtml (create only): 250ms (~ same speed)
replaceHtml (destroy & create): 297ms (50.2x faster)

Creo que los números hablan por sí solos. También se pueden ver mejoras de rendimiento comparables en Safari. En Opera, replaceHtml suele ser más rápido que innerHTML , pero por un margen más estrecho. En IE, uso simple de innerHTML suele ser más rápido que mezclarlo con métodos DOM, pero no por los mismos tipos de márgenes que puede ver arriba. Sin embargo, la función de compilación condicional de IE se usa para evitar la penalización de rendimiento relativamente menor, simplemente usando innerHTML con ese navegador.


No