多JS文件下Firebase缓存数组更新后未正常返回问题咨询
问题描述
我有3个独立的JS文件,其中一个文件导出两个函数供另外两个文件调用:
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; } }
updateDisplayedSub函数:用于更新mySub数组,代码如下:
export function updateDisplayedSub(coursename, section, key, enrolledStudents) { mySub.push([coursename, section, key, enrolledStudents]); }
当前问题:调用updateDisplayedSub更新mySub数组后,再次调用getMySub(id),函数并未返回更新后的缓存数组,而是重新从数据库读取数据。
疑问:跨JS文件调用这两个函数是否会影响缓存?我的需求是减少Firebase数据库读取量,节省免费额度的带宽。
问题分析与解决
核心问题原因
- 异步逻辑漏洞:
getMySub中的Firebase请求是异步操作,第一次调用时,函数会在请求完成前就返回空的mySub数组。后续如果mySub被意外清空(比如模块重新加载、逻辑错误重置),就会触发重新请求。 - 多id场景缓存冲突:现有逻辑用单一数组存储缓存,若调用
getMySub时传入不同id,会导致缓存数据混乱——比如第一次用idA填充数组后,第二次用idB调用时,因数组不为空直接返回idA的数据,后续若清空数组又会重新请求。 - 跨文件调用不影响缓存: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
相关产品推荐
相关产品推荐

