JavaScript递归统计DOM节点 文本/空白/总节点计数少1问题
问题描述
开发JavaScript课程项目时,通过递归函数遍历页面article元素内所有节点构建节点树,调用makeBranches函数统计总节点数、元素节点、文本节点、空白节点数量,最终将结果渲染到页面指定段落。运行代码后仅元素节点计数正确,总节点、文本节点、空白节点的统计值均比预期值少1。
预期正确统计结果:
- 总节点:238个
- 元素节点:98个
- 文本节点:140个
- 空白节点:57个
实际运行时除元素节点外,其余三类计数均比预期少1。
问题原因
- 脚本加载时机问题:你在head中引入脚本时添加了
async属性,该属性会让浏览器并行下载脚本、不阻塞DOM解析,但脚本下载完成后会立即执行,执行顺序不受保证。虽然绑定了window.onload事件触发统计函数,但在部分浏览器内核实现中,若async脚本下载耗时极短,会在DOM树收尾解析阶段(即</article>标签前的最后一个空白文本节点被加入DOM树前)就完成事件绑定,等到onload触发时,统计逻辑会漏掉这个根容器末尾的空白文本节点,最终导致总节点、文本节点、空白节点计数各少1;而元素节点解析优先级更高,已经全部加入DOM树,因此计数保持正确。 - HTML标签笔误问题:你提供的代码中表格内
nextSibling对应的代码标签存在闭合错误:<td><code><em>node</em>.nextSibling</code</td>,</code缺少闭合尖括号>,浏览器自动修正DOM结构时可能出现节点解析偏差,也会导致计数异常。
修复方案
可按以下步骤修复,选择对应方案即可:
- 修正脚本加载配置:移除脚本标签的
async属性,要么使用默认同步加载,要么添加defer属性保证脚本在DOM完全解析完成后再执行:
也可以直接将脚本标签移动到<!-- 方案1:移除async,默认同步加载 --> <script src="js_tree.js"></script> <!-- 方案2:使用defer属性,DOM解析完成后执行脚本 --> <script src="js_tree.js" defer></script></body>标签前引入,此时DOM树已经完全解析完成,不会出现节点漏统计问题。 - 修正HTML笔误:补全未闭合的code标签,避免浏览器解析异常:
<td><code><em>node</em>.nextSibling</code></td> - 优化计数逻辑(可选):在统计函数执行前显式重置全局计数变量,避免页面热更新、脚本重复执行时出现计数累加问题:
function makeTree() { // 每次执行前重置计数 nodeCount = 0; elemCount = 0; textCount = 0; wsCount = 0; var nodeList = document.createElement("ol"); var sourceArticle = document.querySelector("#main article"); makeBranches(sourceArticle, nodeList); // 原有渲染逻辑保持不变 document.getElementById("totalNodes").innerHTML = nodeCount; document.getElementById("elemNodes").innerHTML = elemCount; document.getElementById("textNodes").innerHTML = textCount; document.getElementById("wsNodes").innerHTML = wsCount; }
内容的提问来源于stack exchange,提问作者Matthew Wheeler
相关产品推荐
相关产品推荐

