容错恢复不是“猜”,而是按html living standard状态机执行:解析器依据插入模式和开放元素栈确定性处理未闭合标签,如hello中因是块级元素且禁止嵌套块级元素,立即隐式闭合;等特殊元素遇块级兄弟节点即闭合,等普通元素由栈机制强制收尾,合法而的/被丢弃。

容错恢复不是“猜”,而是按HTML Living Standard状态机执行
浏览器解析器从不靠启发式猜测来闭合标签,它严格依据HTML Living Standard定义的插入模式(insertion modes)和开放元素栈(stack of open elements)推进。遇到未闭合标签时,不是“补上一个
”,而是根据当前栈顶元素类型和下一个token的语义,决定是否生成隐含结束标签(generate implied end tags)。比如在<p>hello</p>
<div>中,<code><div>是块级元素,而<code><p></p>不允许包含块级子元素,所以解析器立刻弹出<p></p>并隐式闭合它——这个动作由状态机驱动,每一步都可复现。
不同元素触发容错的规则完全不同
元素分类直接决定容错行为:
-
<p></p>、<dt></dt>、<li>属于“特殊元素”,遇块级兄弟节点(如另一个<p></p>或<div>)立即隐式闭合 <li><code><div>、<code><span></span>等普通流元素不会主动触发前序元素闭合,但会在父元素闭合或文档结束时被栈机制强制收尾 -
<img>、<br>是void element,<img>合法;而<div></div>中的/会被直接丢弃,等价于<div>,后续内容全归入其子树 <h3>Gumbo和<a style="color:#f60; text-decoration:underline;" title="html" href="https://m.php.cn/zt/15763.html" target="_blank">html</a>5-parser怎么记录错误却不中断解析</h3> <p>它们的错误恢复不是“跳过错误”,而是“登记+状态重置”:</p> <ul> <li>每个错误(如<code>GUMBO_ERR_MISSING_ATTRIBUTE_VALUE)通过parser_add_parse_error()写入parser->errors数组 - 同时根据当前插入模式切换内部状态,确保后续token仍能进入正确处理分支
- 例如在
<table>上下文中遇到<code><div>,解析器不会终止,而是登记错误、保持<code><table>栈帧,并将<code><div>当作“忽略内容”处理 <li>Python的<code>html5-parser通过max_errors参数控制是否继续,但默认始终尽力构造DOM树 -
window.onerror、addEventListener('error')只响应资源加载失败、JS异常、Promise rejection -
DOMParser().parseFromString(htmlStr, 'text/html')永远返回Document对象,哪怕输入是<foo><bar></bar></foo> - 所谓“页面白屏”或“布局错乱”,根源是解析后DOM结构与预期不符,而非错误被抛出——你看到的是容错结果,不是错误本身
- 真正有效的防控只有两类:开发期用
html-validate静态检查,运行时靠doc.body.children.length === 0等简单反推做兜底
为什么你不能用try-catch捕获HTML解析错误
因为HTML解析阶段根本不在JavaScript执行上下文中运行:
<header><nav><ul></ul></nav></header>后面没写,浏览器会自动补全,但屏幕阅读器依赖的嵌套层级可能已错位。这种问题无法靠运行时捕获,只能靠开发期工具链卡死。











