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

使用Geofire结合Firebase实时数据库时出现调用栈溢出错误求助

问题:Firebase实时数据库结合Geofire出现调用栈溢出错误

错误信息

RangeError: Maximum call stack size exceeded
at ChildrenNode.isLeafNode (api/node_modules/firebase-admin/node_modules/@firebase/database-compat/dist/index.standalone.js:8956:50)
at ChildrenNode.equals (api/node_modules/geofire/dist/geofire/index.cjs.js:8461:24)

原示例代码

while (some amount) { 
 geoDriverId = await(new Promise((resolve, reject) => {
try {
  geoDriverId = []
  geoDriverIds = []
  const geoQuery = config.firebase.table.query({
    center: [parseFloat(pick_up_latitude), parseFloat(pick_up_longitude)],
    radius: i
  })
  let listener = geoQuery.on("key_entered", (key, location, distance) => {
    geoDriverIds.push({ key, distance });
  });
  geoQuery.on("ready", (key, location, distance) => {
    listener.cancel();
    geoQuery.cancel();
    resolve(geoDriverIds);
    return;
  });
} catch (e) {
  console.log("e", e)
}
}))
}

错误原因分析

  • 循环内重复创建查询且清理不彻底:while循环中每次迭代都新建GeoQuery和监听器,尽管在ready回调中执行了cancel操作,但异步清理可能存在延迟,旧的监听器仍可能触发,导致Geofire内部递归比较逻辑不断执行,最终栈溢出。
  • Geofire内部递归逻辑异常:ChildrenNode.equals方法用于比较数据节点,当数据库中存在异常数据结构(如循环引用、不符合Geofire规范的嵌套节点)时,递归比较无法终止,引发栈溢出。
  • 变量作用域混乱:geoDriverIds未在Promise内部声明为局部变量,循环迭代时可能被闭包意外引用,导致回调逻辑重复触发。

解决方案

1. 优化循环与查询清理逻辑

避免在循环内重复创建查询,确保每次查询完成后彻底清理所有监听器,防止资源泄漏和重复回调。

2. 修复变量作用域问题

在Promise内部声明局部变量存储结果,避免外部变量污染。

3. 检查数据库数据结构

确保Firebase中存储的Geofire数据符合规范:每个位置节点需为{g: 地理哈希字符串, l: [纬度, 经度]}格式,不存在循环引用或异常嵌套节点。

4. 升级依赖版本

检查firebase-admin和geofire的版本兼容性,升级至最新稳定版,官方可能已修复递归栈溢出的已知bug。

修改后的示例代码

let currentRadius = 1; // 初始搜索半径
const maxRadius = 10; // 最大搜索半径
let nearbyDrivers = [];

// 仅在未找到数据且未达最大半径时继续搜索
while (nearbyDrivers.length === 0 && currentRadius <= maxRadius) {
  nearbyDrivers = await new Promise((resolve, reject) => {
    try {
      const drivers = [];
      const geoQuery = config.firebase.table.query({
        center: [parseFloat(pick_up_latitude), parseFloat(pick_up_longitude)],
        radius: currentRadius
      });

      // 监听进入范围的节点
      const keyEnteredListener = geoQuery.on("key_entered", (key, location, distance) => {
        drivers.push({ key, distance });
      });

      // 查询完成时清理并返回结果
      const readyListener = geoQuery.on("ready", () => {
        keyEnteredListener.cancel();
        readyListener.cancel();
        geoQuery.cancel();
        resolve(drivers);
      });

      // 捕获查询错误
      geoQuery.on("error", (error) => {
        keyEnteredListener.cancel();
        readyListener.cancel();
        geoQuery.cancel();
        reject(error);
      });
    } catch (err) {
      console.error("附近司机查询失败:", err);
      reject(err);
    }
  });

  currentRadius++; // 扩大半径继续搜索
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 22:00:58