Když innerHTML není dostatečně rychlé

Tento příspěvek není o výhodách a nevýhodách innerHTML vs. metody W3C DOM. To bylo hašováno a přehodnocováno jinde. Místo toho ukážu, jak můžete kombinovat použití innerHTML a metody DOM, aby byl váš kód potenciálně stokrát rychlejší než innerHTML při práci s velkým počtem prvků.

V některých prohlížečích (zejména Firefox), ačkoli innerHTML je obecně mnohem rychlejší než metody DOM, tráví neúměrně mnoho času odstraňováním existujících prvků oproti vytváření nových. Když to víme, můžeme kombinovat rychlost ničení prvků odstraněním jejich rodiče pomocí standardních metod DOM s vytvářením nových prvků pomocí innerHTML . (Tato technika je něco, co jsem objevil během vývoje RegexPal, a je jednou z jeho dvou hlavních optimalizací výkonu. Druhou je jednorázové generování značek pro zvýraznění shody, díky čemuž není nutné opakovat shody nebo na ně odkazovat jednotlivě.)

Kód:

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;
};

Výše uvedené můžete použít jako el = replaceHtml(el, newHtml) místo el.innerHTML = newHtml .

innerHTML je již poměrně rychlý...je to skutečně zaručeno?

To záleží na tom, kolik prvků přepisujete. V RegexPal každá událost keydown potenciálně spouští zničení a vytvoření tisíců prvků (aby fungovala syntaxe a zvýraznění shody). V takových případech má výše uvedený přístup obrovský pozitivní dopad. Dokonce i něco tak jednoduchého jako el.innerHTML += str nebo el.innerHTML = "" může být výkonová katastrofa, pokud prvek, který aktualizujete, má několik tisíc dětí.

Vytvořil jsem stránku, která vám umožní snadno otestovat rozdíl ve výkonu innerHTML a můj replaceHtml funkce s různým počtem prvků. Nezapomeňte to vyzkoušet v několika prohlížečích pro srovnání. Následuje několik příkladů typických výsledků z Firefoxu 2.0.0.6 v mém systému:

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)

Myslím, že čísla mluví sama za sebe. Srovnatelné zlepšení výkonu lze vidět také v Safari. V Opeře replaceHtml je stále obvykle rychlejší než innerHTML , ale s užším okrajem. V IE jednoduché použití innerHTML je obvykle rychlejší než smíchání s metodami DOM, ale ne o téměř stejné druhy okrajů, jak můžete vidět výše. Nicméně funkce podmíněné kompilace IE se používá, aby se zabránilo relativně malému snížení výkonu, a to pouhým použitím innerHTML s tímto prohlížečem.


No