Pokaždé innerHTML
je nastaveno, HTML musí být analyzováno, vytvořen DOM a vložen do dokumentu. To chce čas.
Pokud například elm.innerHTML
má tisíce divů, tabulek, seznamů, obrázků atd., pak volá .innerHTML += ...
způsobí, že analyzátor znovu analyzuje všechny tyto věci znovu. To by také mohlo narušit odkazy na již zkonstruované prvky DOM a způsobit další chaos. Ve skutečnosti vše, co chcete udělat, je přidat jeden nový prvek na konec.
Je lepší zavolat appendChild
:
var newElement = document.createElement('div');
newElement.innerHTML = '<div>Hello World!</div>';
elm.appendChild(newElement);
Tímto způsobem stávající obsah elm
nejsou znovu analyzovány.
POZNÁMKA: Je možné, že [některé] prohlížeče jsou dostatečně chytré na to, aby optimalizovaly +=
operátora a znovu neanalyzovat existující obsah. Toto jsem nezkoumal.
Ano, elm.innerHTML += str;
je velmi špatný nápad.
Použijte elm.insertAdjacentHTML( 'beforeend', str )
jako dokonalá alternativa.
Typická odpověď „prohlížeč musí znovu sestavit DOM“ otázku skutečně nesplňuje:
-
Prohlížeč musí nejprve projít všechny prvky pod jilmem, každou z jejich vlastností a všechny jejich texty, komentáře a zpracovat uzly a opustit je, aby vám sestavil řetězec.
-
Pak máte dlouhý řetězec, ke kterému připojíte. Tento krok je v pořádku.
-
Za třetí, když nastavíte innerHTML, prohlížeč musí odstranit všechny prvky, vlastnosti a uzly, kterými právě prošel.
-
Poté analyzuje řetězec, sestaví ze všech prvků, vlastností a uzlů, které právě zničil, a vytvoří nový fragment DOM, který je většinou identický.
-
Nakonec připojí nové uzly a prohlížeč to musí celé rozvrhnout. Tomu se lze vyhnout (viz alternativa níže), ale i když připojené uzly vyžadují rozvržení, staré uzly budou mít vlastnosti rozvržení uloženy do mezipaměti namísto přepočítání z čerstvého.
-
Ale ještě není hotovo! Prohlížeč musí také recyklovat staré uzly skenováním všech javascriptové proměnné.
Problémy:
-
Některé vlastnosti nemusí HTML odrážet, například aktuální hodnota
<input>
budou ztraceny a obnoveny na původní hodnotu v HTML. -
Pokud máte na starých uzlech nějaké ovladače událostí, budou zničeny a budete je muset všechny znovu připojit.
-
Pokud váš kód js odkazuje na nějaké staré uzly, nebudou zničeny, ale budou osiřely. Patří k dokumentu, ale již nejsou ve stromu DOM. Když k nim váš kód přistoupí, nemusí se nic stát nebo může způsobit chybu.
-
Oba problémy znamenají, že to není přátelské k zásuvným modulům js – zásuvné moduly mohou připojit obslužné nástroje nebo uchovávat odkazy na staré uzly a způsobit únik paměti.
-
Pokud si zvyknete manipulovat DOM pomocí innerHTML, můžete náhodně změnit vlastnosti nebo dělat jiné věci, které jste nechtěli.
-
Čím více uzlů máte, tím je to neefektivnější, tím více šťávy z baterie pro nic za nic.
Stručně řečeno, je neefektivní, je náchylný k chybám, je prostě líný a neinformovaný.
Nejlepší alternativou je Element.insertAdjacentHTML
, které jsem neviděl zmiňovat jiné odpovědi:
elm.insertAdjacentHTML( 'beforeend', str )
Téměř stejný kód, bez problémů s innerHTML. Žádné přestavby, žádná ztráta obsluhy, žádné resetování vstupu, menší fragmentace paměti, žádný zlozvyk, žádné ruční vytváření a přiřazování prvků.
Umožňuje vkládat html řetězec do prvků v jednom řádku, včetně vlastností, a dokonce umožňuje vkládat kompozitní a vícenásobné prvky. Jeho rychlost je optimalizována - v testu Mozilly je 150 krát rychleji.
V případě, že vám někdo řekne, že nejde o různé prohlížeče, je to tak užitečné, že je to standard HTML5 a je k dispozici ve všech prohlížečích.
Nikdy nepište elm.innerHTML+=
znovu.
Alternativou je .createElement()
, .textContent
a .appendChild()
. Přidávání pomocí +=
je problém pouze v případě, že pracujete s velkým množstvím dat.
Ukázka: http://jsfiddle.net/ThinkingStiff/v6WgG/
Skript
var elm = document.getElementById( 'targetID' ),
div = document.createElement( 'div' );
div.textContent = 'goodbye world';
elm.appendChild( div );
HTML
<div id="targetID">hello world</div>