Firebase V9离线调用setDoc未触发catch抛出错误如何解决
问题根因
Firebase Firestore 默认开启了离线持久化能力,当你调用 setDoc 这类写入接口时,如果用户处于离线状态,Firestore 会先将写入操作暂存到本地缓存队列,待网络恢复后自动同步到服务端。这个设计下 setDoc 返回的 Promise 不会因为离线直接抛出错误,自然不会进入 catch 分支。
而 Authentication 相关接口没有本地操作队列的设计,所有鉴权请求都需要实时和服务端交互,因此离线时会直接返回网络错误进入 catch。
解决方案
方案1:监听文档同步状态,区分本地暂存和服务端写入
如果你的需求是既要保留Firestore离线能力,又要区分「操作已离线暂存」和「已成功写入服务端」两种状态,可以通过 onSnapshot 监听目标文档的元数据,判断是否存在待同步的写入:
import { doc, onSnapshot, setDoc } from "firebase/firestore"; const cityRef = doc(db, "cities", "new-city-2"); try { // 离线状态下操作会存入本地队列,不会抛错 await setDoc(cityRef, data); console.log("操作已存入本地队列,网络恢复后自动同步"); // 可在这里先设置离线暂存对应的状态 // 监听同步状态 const unsub = onSnapshot(cityRef, (snapshot) => { if (snapshot.metadata.hasPendingWrites) { // 数据仍为本地暂存状态,未同步到服务端 console.log("数据暂存本地,尚未同步"); } else { // 所有写入已成功同步到服务端 console.log("数据已写入服务端"); unsub(); // 不需要继续监听可取消订阅 } }); } catch (err) { // 仅权限不足、参数非法等业务错误会进入此分支 console.log(`写入失败: ${err}`); }
方案2:提前检测网络状态做拦截
如果只需要在调用接口前对离线状态做提前拦截提示,可以直接使用浏览器自带的网络状态API:
try { if (!navigator.onLine) { throw new Error("网络已断开,请连接网络后重试"); } await setDoc(doc(db, "cities", "new-city-2"), data) console.log("Document Written Successfully"); } catch (err) { console.log(`error found! ${err}`); // 在这里设置对应错误状态即可 }
注意:此方法判断有局限性,用户连接无外网的WiFi时会误判为在线状态。
方案3:禁用离线持久化(不推荐)
如果你完全不需要Firestore的离线使用能力,可以在初始化时关闭离线持久化,此时离线调用 setDoc 会直接抛出网络错误进入catch:
import { initializeFirestore } from "firebase/firestore"; const db = initializeFirestore(app, { persistence: false // 关闭离线持久化 });
注意:关闭后所有Firestore操作都需要实时联网,离线状态下无法正常使用,会丢失Firestore核心的离线使用优势。
内容的提问来源于stack exchange,提问作者Muhammad Ameen
相关产品推荐
相关产品推荐

