Proč je element.innerHTML+=špatný kód?

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:

  1. 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.

  2. Pak máte dlouhý řetězec, ke kterému připojíte. Tento krok je v pořádku.

  3. Za třetí, když nastavíte innerHTML, prohlížeč musí odstranit všechny prvky, vlastnosti a uzly, kterými právě prošel.

  4. 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ý.

  5. 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.

  6. 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>