Verstehe, wie der Browser jeden HTML-Stream, selbst einen fehlerhaften, in einen deterministischen DOM-Baum verwandelt.
Diese Lektion in Kodokon öffnenAnders als XML kennt HTML keinen fatalen Fehler: Die WHATWG-Spezifikation legt Byte für Byte fest, wie jeder Eingabestream - selbst ein fehlerhafter - zu einem DOM-Baum werden muss. Der Parser arbeitet in zwei Stufen: Der Tokenizer zerlegt den Stream in Tokens (Tags, Text, Kommentare), dann fügt der Tree Builder sie gemäß einer Zustandsmaschine ein, deren Zustände Insertion Modes heißen (in body, in table und so weiter). Jeder „Parse-Fehler“ hat eine standardisierte Behebung: Zwei konforme Browser erzeugen exakt dasselbe DOM.
<table>
<tr><td>Cell</td></tr>
</table>Der Parser fügt implizite Tags ein: Ein <tbody> erscheint um die Zeilen herum, und <li>, <p> oder <option> schließen sich automatisch vor bestimmten öffnenden Tags. Noch radikaler: Jeder Inhalt, der sich in einer <table> an einer nicht erlaubten Stelle befindet, wird herausgezogen und direkt davor wieder eingefügt - ein Mechanismus namens Foster Parenting. Deine CSS-Selektoren und deine Skripte arbeiten immer auf dem korrigierten DOM, nie auf deiner Quelle.
const html =
"<table><div>out</div><tr><td>ok</td></tr></table>";
const doc = new DOMParser()
.parseFromString(html, "text/html");
console.log(doc.body.innerHTML);
// <div>out</div><table>...</table>Falsch verschachtelte Formatierungs-Tags lösen den Adoption Agency Algorithm aus, einen der hinterhältigsten Teile der Spezifikation: Der Parser klont die aktiven Formatierungselemente und verteilt sie neu, um einen korrekt verschachtelten Baum zu erzeugen. Das gekreuzte Markup unten zeigt das Ergebnis.
<p>
<b>One <i>two</b> three</i>
</p><b>One <i>two</i></b><i> three</i> - das i wird in zwei Elemente aufgeteilt.Der Parser ist ein Streaming-Parser: Er baut den Baum auf, während die Bytes eintreffen. Ein synchrones <script> hält ihn an - das Skript kann document.write aufrufen und Tokens in den Stream einschleusen -, aber der Preload Scanner durchkämmt weiterhin das restliche HTML, um Bilder, Stylesheets und Skripte vorzuladen. Wird document.write nach dem Ende des Parsings aufgerufen, löst es document.open aus und löscht die gesamte Seite: Es ist eine der ältesten Fallen der Plattform.
<div> in <table><div>Out</div><tr><td>A</td></tr></table>?<td>-Zelle verpackt<p><div>X</div></p>?<p></p><div>X</div><p></p>: Das div schließt das erste p, und das verwaiste </p> erzeugt ein zweites, leeres<p><div>X</div></p>, unverändert beibehalten<div><p>X</p></div>, der Parser kehrt die Verschachtelung um