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

多JS文件下Firebase缓存数组更新后未正常返回问题咨询

问题描述

我有3个独立的JS文件,其中一个文件导出两个函数供另外两个文件调用:

  1. getMySub函数:首次调用时从Firebase实时数据库拉取数据并存入全局数组mySub,后续调用本应直接返回该缓存数组,代码如下:
let mySub = [];
export function getMySub(id) { // get users subjects
  if (mySub.length !== 0) {
    console.log('From Array SUBJECTS');
    return mySub;
  } else if (mySub.length == 0) {
    get(child(path, "General")).then((snapshot) => {
      snapshot.forEach(function(childSnapshot) {
        var data = childSnapshot.val();
        if (data.INS_SYS_ID == id) {
          mySub.push([data.COURSE_NAME, data.SECTION, childSnapshot.key, data.ENROLLED_STUDENTS]);
        }
      })
    }).catch((error) => {
      console.error(error);
    });
    console.log('From DB SUBJECTS');
    return mySub;
  }
}
  1. updateDisplayedSub函数:用于更新mySub数组,代码如下:
export function updateDisplayedSub(coursename, section, key, enrolledStudents) {
  mySub.push([coursename, section, key, enrolledStudents]);
}

当前问题:调用updateDisplayedSub更新mySub数组后,再次调用getMySub(id),函数并未返回更新后的缓存数组,而是重新从数据库读取数据。

疑问:跨JS文件调用这两个函数是否会影响缓存?我的需求是减少Firebase数据库读取量,节省免费额度的带宽。


问题分析与解决

核心问题原因

  1. 异步逻辑漏洞:getMySub中的Firebase请求是异步操作,第一次调用时,函数会在请求完成前就返回空的mySub数组。后续如果mySub被意外清空(比如模块重新加载、逻辑错误重置),就会触发重新请求。
  2. 多id场景缓存冲突:现有逻辑用单一数组存储缓存,若调用getMySub时传入不同id,会导致缓存数据混乱——比如第一次用idA填充数组后,第二次用idB调用时,因数组不为空直接返回idA的数据,后续若清空数组又会重新请求。
  3. 跨文件调用不影响缓存:ES模块是单例模式,同一个模块导出的函数共享全局变量mySub,跨文件调用不会导致缓存失效,问题不在跨文件调用本身。

修正方案

方案1:支持多id的缓存方案(推荐)

用对象存储不同id的缓存数据,同时处理异步请求的重复触发问题:

// 缓存不同id的数据,同时标记请求状态避免重复请求
const subCache = {};
const loadingFlags = {};

export async function getMySub(id) {
  // 已有缓存直接返回
  if (subCache[id]) {
    console.log('From Cache SUBJECTS');
    return subCache[id];
  }

  // 正在请求中,等待请求完成
  if (loadingFlags[id]) {
    await new Promise(resolve => setTimeout(resolve, 50));
    return getMySub(id);
  }

  loadingFlags[id] = true;
  try {
    const snapshot = await get(child(path, "General"));
    const dataList = [];
    snapshot.forEach(childSnapshot => {
      const data = childSnapshot.val();
      if (data.INS_SYS_ID === id) {
        dataList.push([data.COURSE_NAME, data.SECTION, childSnapshot.key, data.ENROLLED_STUDENTS]);
      }
    });
    subCache[id] = dataList;
    console.log('From DB SUBJECTS');
    return dataList;
  } catch (error) {
    console.error(error);
    throw error;
  } finally {
    loadingFlags[id] = false;
  }
}

export function updateDisplayedSub(id, coursename, section, key, enrolledStudents) {
  // 对应id的缓存不存在则初始化
  if (!subCache[id]) subCache[id] = [];
  subCache[id].push([coursename, section, key, enrolledStudents]);
}

方案2:单id场景简化修复

如果业务中只会用同一个id调用getMySub,可修改原有逻辑保证异步请求完成后缓存生效:

let mySub = [];
let isLoading = false;

export async function getMySub(id) {
  if (mySub.length !== 0) {
    console.log('From Array SUBJECTS');
    return mySub;
  }

  if (isLoading) {
    await new Promise(resolve => setTimeout(resolve, 50));
    return getMySub(id);
  }

  isLoading = true;
  try {
    const snapshot = await get(child(path, "General"));
    snapshot.forEach(childSnapshot => {
      const data = childSnapshot.val();
      if (data.INS_SYS_ID === id) {
        mySub.push([data.COURSE_NAME, data.SECTION, childSnapshot.key, data.ENROLLED_STUDENTS]);
      }
    });
    console.log('From DB SUBJECTS');
    return mySub;
  } catch (error) {
    console.error(error);
    throw error;
  } finally {
    isLoading = false;
  }
}

export function updateDisplayedSub(coursename, section, key, enrolledStudents) {
  mySub.push([coursename, section, key, enrolledStudents]);
}

关键注意事项

  • 用async/await处理异步逻辑,避免函数提前返回未填充的数组
  • 添加加载状态标记,防止同一请求被重复触发
  • 多id场景必须用对象映射缓存,不能用单一数组
  • ES模块单例特性保证跨文件调用共享缓存,无需担心跨文件导致的缓存失效

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 05:55:16