React Native中GeoFirestore查询用Promise.race加超时失效的解决方法
为GeoFirestore查询添加可靠的超时与取消机制
问题背景
用React Native + Expo开发的App,通过GeoFirestore从Firebase Firestore按距离排序查询活跃用户时,偶尔会因查询耗时过长导致App崩溃。尝试用Promise.race结合超时Promise实现超时控制,但部分场景下超时未生效,且即使超时,后台查询可能仍在执行,持续占用资源。
解决方案:结合超时与查询取消
核心思路是不仅要触发超时逻辑,还要主动取消正在进行的GeoFirestore查询,避免后台操作持续占用资源导致崩溃。利用AbortController实现查询取消,配合Promise.race完成超时控制。
1. 封装带取消功能的超时工具函数
// 封装通用的超时取消工具 const withTimeout = (promiseFn, timeoutMs) => { const controller = new AbortController(); const timeoutPromise = new Promise((_, reject) => { const timeoutId = setTimeout(() => { controller.abort(); // 超时后主动取消原查询 reject(new Error('查询超时')); }, timeoutMs); // 原操作完成后清理超时定时器 promiseFn(controller.signal) .then(() => clearTimeout(timeoutId)) .catch(() => clearTimeout(timeoutId)); }); const operationPromise = promiseFn(controller.signal); return Promise.race([operationPromise, timeoutPromise]); };
2. 修改GeoFirestore查询代码
import { GeoFirestore } from 'geofirestore'; // GeoFirestore 3.4.1 import { getFirestore } from 'firebase/firestore'; getUsersByDistance = async (location, radius) => { try { const firestore = getFirestore(); const geofirestore = new GeoFirestore(firestore); const activeUsers = geofirestore.collection('users').where('userStatus', '==', 'active'); // 构建距离查询 const query = activeUsers.near({ center: new firestore.GeoPoint(location.latitude, location.longitude), radius }); // 执行带5秒超时的查询 const result = await withTimeout(async (signal) => { // 给查询传入AbortSignal,支持取消 return query.get({ signal }); }, 5000); // 处理查询结果 const users = result.docs.map(doc => doc.data()); console.log('获取到的用户:', users); return users; } catch (e) { if (e.name === 'AbortError') { console.log('查询因超时被取消'); // 这里可以添加超时后的降级逻辑,比如缩小半径重试 } else { console.log('查询失败:', e.message); } return []; } };
关键说明
- AbortController的作用:React Native/Expo完全支持这个API,它能主动终止Firestore的
get()请求,避免超时后后台查询仍在占用网络或内存资源,从根源上解决超时导致的崩溃问题。 - 定时器清理:原查询完成后会自动清理超时定时器,避免内存泄漏。
- 错误区分:通过
e.name === 'AbortError'可以区分是超时取消还是其他查询错误,方便添加不同的处理逻辑。
额外优化建议
- 限制返回数量:给查询添加
.limit(20)(根据业务调整数量),减少数据传输和处理时间:const query = activeUsers.near(...).limit(20); - 检查索引配置:确保Firestore后台已经创建了GeoFirestore所需的复合索引,避免查询时动态创建索引导致延迟。
- 动态调整半径:根据用户当前场景(比如城市内)缩小查询半径,减少返回的数据量。
内容的提问来源于stack exchange,提问作者user56353
相关产品推荐
相关产品推荐

