ทำความเข้าใจว่าเบราว์เซอร์เปลี่ยนสตรีม HTML ใด ๆ แม้แต่สตรีมที่ผิดรูปแบบ ให้กลายเป็นต้นไม้ DOM ที่แน่นอนได้อย่างไร
เปิดบทเรียนนี้ใน Kodokonต่างจาก XML ตรงที่ HTML ไม่มีสิ่งที่เรียกว่าข้อผิดพลาดร้ายแรง (fatal error): ข้อกำหนดของ WHATWG ระบุทีละไบต์ว่าอินพุตสตรีมใด ๆ แม้แต่ที่ผิดรูปแบบ ต้องกลายเป็นต้นไม้ DOM อย่างไร ตัวparser ทำงานเป็นสองขั้น: tokenizer จะตัดสตรีมออกเป็น token (แท็ก ข้อความ ความคิดเห็น) จากนั้น tree builder จะแทรกพวกมันตามเครื่องสถานะ (state machine) ที่สถานะต่าง ๆ ถูกเรียกว่า insertion modes (in body, in table และอื่น ๆ) ทุก "parse error" มีการกู้คืนที่เป็นมาตรฐาน: เบราว์เซอร์ที่ทำตามข้อกำหนดสองตัวจะสร้าง DOM ที่เหมือนกันเป๊ะ
<table>
<tr><td>Cell</td></tr>
</table>ตัว parser จะแทรกแท็กโดยปริยาย: <tbody> จะปรากฏรอบ ๆ แถว และ <li>, <p> หรือ <option> จะปิดตัวเองโดยอัตโนมัติเมื่ออยู่หน้าแท็กเปิดบางตัว ที่รุนแรงยิ่งกว่านั้น: เนื้อหาใด ๆ ที่พบภายใน <table> ในตำแหน่งที่ไม่ได้รับอนุญาต จะถูก ดึงออก จากมันแล้วแทรกกลับเข้าไปใหม่ก่อนหน้าตาราง กลไกนี้เรียกว่า foster parenting ตัวเลือก CSS และสคริปต์ของคุณทำงานบน DOM ที่แก้ไขแล้วเสมอ ไม่ใช่บนซอร์สของคุณ
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>แท็กจัดรูปแบบที่ซ้อนกันผิดจะกระตุ้น adoption agency algorithm ซึ่งเป็นหนึ่งในส่วนที่ซับซ้อนที่สุดของข้อกำหนด: ตัว parser จะโคลนและกระจายองค์ประกอบจัดรูปแบบที่กำลังทำงานอยู่ใหม่ เพื่อสร้างต้นไม้ที่ซ้อนกันอย่างถูกต้อง มาร์กอัปที่ไขว้กันด้านล่างแสดงผลลัพธ์
<p>
<b>One <i>two</b> three</i>
</p><b>One <i>two</i></b><i> three</i> - ตัว i ถูกแยกออกเป็นสององค์ประกอบตัว parser เป็น parser แบบ streaming: มันสร้างต้นไม้ขึ้นมาขณะที่ไบต์ทยอยมาถึง <script> แบบซิงโครนัสจะระงับมันไว้ - สคริปต์สามารถเรียก document.write และฉีด token เข้าไปในสตรีมได้ - แต่ preload scanner ยังคงกวาดผ่าน HTML ที่เหลือเพื่อโหลดล่วงหน้าซึ่งรูปภาพ สไตล์ชีต และสคริปต์ หากเรียกหลังจาก parsing เสร็จสิ้นแล้ว document.write จะกระตุ้น document.open และล้างทั้งหน้าทิ้ง: มันเป็นหนึ่งในกับดักที่เก่าแก่ที่สุดของแพลตฟอร์ม
<div> ใน <table><div>Out</div><tr><td>A</td></tr></table>?<td> ที่สร้างขึ้นมาให้<p><div>X</div></p> สร้าง DOM แบบไหน?<p></p><div>X</div><p></p>: ตัว div ปิด p ตัวแรก และ </p> ที่ไร้คู่จะสร้าง p ตัวที่สองซึ่งว่างเปล่า<p><div>X</div></p> คงไว้ตามเดิม<div><p>X</p></div> ตัว parser กลับด้านการซ้อน