Firebase定时函数中实现Firestore文档等待查询及超时返回null
如何实现带超时等待的Firestore文档查询函数?
我已经写了一个能成功查询Firestore数据库文档的Node.js函数,目前用的是.get()方法做一次性查询。现在想改成一个可以等待的触发式函数——一直等到其他应用上传符合条件的文档,同时设置5分钟的超时时间,如果超时还没找到就返回null。当前的函数代码如下:
export const createFinder = async (latitude, longitude, orderUid) => { // Find cities within 5km of location const radiusInM = 50 * 100; const bounds = geofire.geohashQueryBounds([latitude, longitude], radiusInM); const promises = []; for (const b of bounds) { const q = db.collection('availableDocuments') .orderBy('geohash') .startAt(b[0]) .endAt(b[1]); const snapshot = await q.get(); promises.push(snapshot); } return promises; }
实现思路
要实现等待符合条件的文档 + 超时机制,可以结合Firestore的实时监听(onSnapshot)和Promise.race():
- 用
onSnapshot监听所有地理查询的结果,一旦发现符合条件的文档就立即返回 - 同时创建一个超时Promise,5分钟后触发并返回null
- 用
Promise.race()让这两个Promise竞争,先触发的结果就是最终返回值 - 注意在查询结束(不管成功还是超时)后清理所有监听,避免内存泄漏
修改后的完整代码
export const createFinderWithTimeout = async (latitude, longitude, orderUid, timeoutMs = 5 * 60 * 1000) => { const radiusInM = 50 * 100; const bounds = geofire.geohashQueryBounds([latitude, longitude], radiusInM); const unsubscribeFunctions = []; // 创建超时Promise const timeoutPromise = new Promise((resolve) => { setTimeout(() => { // 超时后清理所有监听 unsubscribeFunctions.forEach(unsubscribe => unsubscribe()); resolve(null); }, timeoutMs); }); // 创建监听查询的Promise const waitForDocumentPromise = new Promise((resolve, reject) => { // 遍历所有geohash边界查询 bounds.forEach(b => { const q = db.collection('availableDocuments') .orderBy('geohash') .startAt(b[0]) .endAt(b[1]); // 启动实时监听 const unsubscribe = q.onSnapshot(snapshot => { // 遍历查询到的文档,检查实际距离是否在范围内(geohash边界可能包含超出半径的文档) for (const doc of snapshot.docs) { const docData = doc.data(); // 计算当前文档与目标位置的实际距离 const distance = geofire.distance([latitude, longitude], [docData.latitude, docData.longitude]); if (distance * 1000 <= radiusInM) { // 找到符合条件的文档,清理所有监听并返回 unsubscribeFunctions.forEach(unsub => unsub()); resolve(doc); return; } } }, error => { // 监听出错时,清理所有监听并抛出错误 unsubscribeFunctions.forEach(unsub => unsub()); reject(error); }); unsubscribeFunctions.push(unsubscribe); }); }); // 让两个Promise竞争,返回先触发的结果 return Promise.race([waitForDocumentPromise, timeoutPromise]); }
关键细节说明
- 地理距离校验:geohash查询的边界只是近似范围,必须用
geofire.distance()再校验一次实际距离,确保文档确实在目标半径内 - 监听清理:不管是找到文档还是超时,都要调用
unsubscribe()关闭所有实时监听,防止内存泄漏 - 超时配置:默认设置为5分钟,你可以通过第四个参数
timeoutMs自定义超时时间 - 错误处理:监听过程中如果出现错误(比如权限问题),会直接抛出错误,调用时可以用
try/catch捕获
内容的提问来源于stack exchange,提问作者arbis
相关产品推荐
相关产品推荐

