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

AngularFire7 runTransaction报Maximum call stack exceeded错误

问题背景

此前曾发布相关问题帖但该帖已被关闭,检索到其他用户反馈过高度相似的报错,但始终未找到网络上的有效解答。当前使用Firebase Realtime Database,数据库中对应节点结构如下:

private: {
  $user_uid: {
    formula: {
      formula_quota: 30,
      quota_used: 0
    }
  }
}

业务逻辑为按钮触发数据发布操作,发布流程完成后执行事务逻辑读取配额对象并完成更新,以下为配额事务的核心实现代码(已剔除未使用、已注释的无关代码):

quotaTransaction ( userUID:string, projectUID:string, state:EditorState, asObject:boolean, asProject:boolean ) {

    const quotaPath = `/private/${ userUID }/formula`;

    const quotaDoc = ref( this.db, quotaPath );
 
    runTransaction( quotaDoc, quota => {

      let nbPublish = 0;

      if ( asObject ) nbPublish++;
      if ( asProject ) nbPublish++;

      let quotaUsed = quota.quota_used;
      let formulaQuota = quota.formula_quota;

      if ( nbPublish + quotaUsed > formulaQuota ) return ( undefined );

      return ( { quota_used: quotaUsed + nbPublish, formula_quota:formulaQuota } );

    } ).catch( console.log );

}
报错复现
  • 首次执行quotaTransaction方法时,抛出栈溢出错误:

RangeError: Maximum call stack size exceeded
at ChildrenNode.isLeafNode (vendor.js:52413:13)
at ChildrenNode.equals (vendor.js:20990:22)
at ChildrenNode.equals (vendor.js:20995:31)
at ChildrenNode.equals (vendor.js:20995:31)
at ChildrenNode.equals (vendor.js:20995:31)
at ChildrenNode.equals (vendor.js:20995:31)
at ChildrenNode.equals (vendor.js:20995:31)
at ChildrenNode.equals (vendor.js:20995:31)
at ChildrenNode.equals (vendor.js:20995:31)
at ChildrenNode.equals (vendor.js:20995:31)

  • 第二次执行该方法时,抛出路径类型错误:

TypeError: childPathObj.split is not a function
at pathChild (vendor.js:17766:38)
at ImmutableTree.findRootMostMatchingPathAndValue (vendor.js:23435:30)
at ImmutableTree.findRootMostMatchingPathAndValue (vendor.js:23432:51)
at ImmutableTree.findRootMostMatchingPathAndValue (vendor.js:23432:51)
at ImmutableTree.findRootMostValueAndPath (vendor.js:23456:17)
at compoundWriteGetCompleteNode (vendor.js:55532:45)
at compoundWriteChildCompoundWrite (vendor.js:55574:27)
at writeTreeCalcCompleteEventCache (vendor.js:55887:19)
at syncTreeCalcCompleteEventCache (vendor.js:57565:10)
at repoGetLatestState (vendor.js:59219:10)

根因分析

两个报错均由事务回调未覆盖边界场景导致:
Firebase Realtime Database事务首次执行回调时,如果本地没有对应节点的缓存,传入的当前值参数quota会是null。原代码未做判空直接访问quota.quota_used、quota.formula_quota,拿到的是undefined,后续计算得到的更新对象包含NaN、undefined等非法值,触发SDK内部节点递归比较逻辑死循环,直接导致栈溢出。第一次执行失败后本地缓存了异常状态值,第二次执行时就会触发路径解析的类型错误。
额外问题:原代码在配额不足时返回undefined,会被SDK判定为删除当前节点,不符合业务逻辑预期。

修复方案

调整事务回调逻辑,覆盖空值场景、修正返回值,修复后代码如下:

runTransaction( quotaDoc, quota => {
  // 处理本地无缓存、节点不存在的场景
  if (quota === null) {
    // 按业务规则初始化配额值
    return {
      formula_quota: 30,
      quota_used: 0
    }
  }

  let nbPublish = 0;
  if (asObject) nbPublish++;
  if (asProject) nbPublish++;

  // 增加类型兜底,兼容历史脏数据
  const quotaUsed = Number(quota.quota_used) || 0;
  const formulaQuota = Number(quota.formula_quota) || 0;

  // 配额不足时直接返回当前节点值,终止本次更新,不要返回undefined
  if (nbPublish + quotaUsed > formulaQuota) {
    return quota;
  }

  return {
    quota_used: quotaUsed + nbPublish,
    formula_quota: formulaQuota
  };
} )

核心修复点:

  • 事务回调开头必须判断入参是否为null,覆盖本地无缓存、节点首次创建的场景
  • 配额校验不通过时返回当前读取到的节点值,不要返回undefined,避免误删节点
  • 对读取到的配额字段增加类型转换兜底,避免历史脏数据(字段缺失、值类型错误)引发计算异常

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 04:27:25