Firebase Firestore无网络时Promise未触发catch问题求助(React Native/Expo)
问题原因与解决方案
兄弟,这个问题其实是Firestore离线持久化的默认行为在搞鬼,不是你漏了基础知识~
核心原因
Firebase Firestore在React Native/Expo环境中默认开启了离线持久化功能。当你调用docRef.get()时:
- 如果设备离线,且本地缓存中没有这个文档的副本,Firestore会一直挂起这个Promise,等待网络恢复后再尝试从服务器获取数据,不会立即触发
catch回调。 - 只有当网络请求明确失败(比如联网但服务器返回错误),或者你指定了读取来源且来源不可用时,才会进入
catch。
解决办法
你可以通过以下几种方式处理这种情况:
1. 指定读取来源
调用get()时通过source参数明确指定读取缓存还是服务器:
- 只想读缓存:如果缓存里没有该文档,会直接触发
catch
docRef.get({ source: 'cache' }) .then((doc) => { if (doc.exists) { // 处理缓存中的数据 } else { // 缓存中无此文档 alert('No cached data available'); } }) .catch(() => { alert('Please connect to the internet'); });
- 强制读服务器:离线时会直接触发
catch
docRef.get({ source: 'server' }) .then(() => { /* 处理服务器数据 */ }) .catch(() => { alert('Please connect to the internet'); });
2. 先检查网络状态
在调用get()前,先通过Expo的Network模块检查设备是否联网:
import * as Network from 'expo-network'; // 先检查网络 const checkNetwork = async () => { const networkState = await Network.getNetworkStateAsync(); if (!networkState.isConnected) { alert('Please connect to the internet'); return false; } return true; }; // 使用示例 checkNetwork().then((isConnected) => { if (isConnected) { docRef.get() .then(() => { /* 处理数据 */ }); } });
3. 给Promise添加超时
如果不想无限等待,可以自己封装一个带超时的Promise,和Firestore的请求一起用Promise.race:
const withTimeout = (promise, timeoutMs) => { return Promise.race([ promise, new Promise((_, reject) => { setTimeout(() => reject(new Error('Request timed out')), timeoutMs); }) ]); }; // 使用示例 withTimeout(docRef.get(), 5000) // 5秒超时 .then(() => { /* 处理数据 */ }) .catch(() => { alert('Please connect to the internet'); });
内容的提问来源于stack exchange,提问作者juicy89
相关产品推荐
相关产品推荐

