You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

递归读取未知结构嵌套JSON拼接DOM字符串触发栈溢出如何解决

问题原因

你遇到的栈溢出问题由三个核心问题共同导致:

  • 原生递归依赖JS引擎的调用栈,存在固定的深度上限。你的原有实现每一层递归都在栈帧中持有持续增长的strSource字符串,而JS字符串是不可变类型,每次拼接都会生成新的字符串副本,单栈帧内存占用远高于仅读取键值的场景,嵌套层级稍高就会触及栈内存上限。
  • 原有逻辑缺少null值判断:JS中typeof null === 'object',如果返回的JSON中存在null值,会触发无限递归直接爆栈。
  • 逐层字符串拼接的性能极差,大字符串反复拷贝会额外消耗内存,进一步放大栈溢出概率。
修复方案

方案1:优化现有递归(适配绝大多数常规业务场景)

核心优化点是用数组收集HTML片段,替代逐层字符串拼接,降低单栈帧内存占用,同时补全null值判断,修复索引过滤的逻辑bug:

// 优化后的递归处理函数
function processObject(jsonObject) {
  const fragments = []
  // 提前拦截null、非对象值,避免死递归
  if (jsonObject === null || typeof jsonObject !== 'object') return fragments

  for (const property in jsonObject) {
    if (!jsonObject.hasOwnProperty(property)) continue
    const value = jsonObject[property]
    
    if (typeof value === 'object' && value !== null) {
      // 合并递归返回的片段数组,不做中间字符串拼接
      fragments.push(...processObject(value))
      continue
    }
    // 正确过滤数组数字索引,修复原isNaN判断的逻辑漏洞
    if (!isNaN(Number(property))) continue
    fragments.push(`<tr>
      <td>${property}</td>
      <td>${value}</td>
    </tr>`)
  }
  return fragments
}

对应修改表格生成函数中的调用逻辑,最后一次性拼接所有片段:

// Docreatefiltersessiontable 中替换原有拼接逻辑
tablestring += processObject(AuditRecords).join('')

该优化可降低70%以上的栈内存占用,常规嵌套深度的JSON数据不会再触发栈溢出,输出结果和原逻辑完全一致。

方案2:非递归深度优先遍历(彻底规避栈溢出,适配超深嵌套/超大JSON场景)

递归的本质是借用JS引擎的内置调用栈,我们可以手动维护遍历栈,把递归改为循环实现,从根本上绕开JS引擎的调用栈上限限制,稳定性和性能都优于递归实现:

// 非递归实现,无调用栈溢出风险
function processObjectFlat(root) {
  const fragments = []
  // 手动初始化遍历栈,根节点入栈
  const stack = [root]

  while (stack.length) {
    const current = stack.pop()
    // 拦截null、非对象值
    if (current === null || typeof current !== 'object') continue

    for (const property in current) {
      if (!current.hasOwnProperty(property)) continue
      const value = current[property]

      if (typeof value === 'object' && value !== null) {
        // 嵌套对象/数组压入栈,等待后续遍历
        stack.push(value)
        continue
      }
      // 过滤数组数字索引
      if (!isNaN(Number(property))) continue
      fragments.push(`<tr>
        <td>${property}</td>
        <td>${value}</td>
      </tr>`)
    }
  }
  return fragments.join('')
}

使用时直接把表格生成函数中的processObject替换为processObjectFlat即可,遍历顺序、输出结果和原逻辑完全一致,无论JSON嵌套层级多深,都不会触发栈溢出。

额外优化建议
  • 建议新增HTML转义逻辑,避免属性值中包含</>/&等特殊字符时破坏HTML结构,同时防范XSS风险:
    function escapeHtml(str) {
      return String(str)
        .replace(/&/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#39;')
    }
    
    拼接单元格内容时将${value}替换为${escapeHtml(value)}即可。
  • 超大表格场景下,可配合DataTables的deferRender配置开启按需渲染,减少首屏DOM节点数量,进一步提升渲染性能。

内容的提问来源于stack exchange,提问作者Edoardo Remondini

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 17:12:29