如何用navigator.sendBeacon()执行函数?窗口关闭时更新Firestore文档
窗口关闭时更新Firestore文档的可行方案
直接在窗口关闭事件中调用Firestore的updateDoc大概率会失败——因为浏览器在窗口卸载时会终止未完成的异步任务,而Firestore SDK的方法没有内置keepalive机制来保证请求完成。以下是几种可靠的实现方式:
方案一:通过自建后端接口中转(推荐)
利用navigator.sendBeacon()的可靠发送能力,将更新数据发给自己的后端服务,再由后端调用Firestore完成文档更新。
前端代码示例
window.addEventListener('unload', () => { // 准备要更新的数据和目标文档ID const updatePayload = JSON.stringify({ docId: 'target-doc-id', lastActive: new Date().toISOString(), // 其他需要更新的字段 }); // 发送到自建后端接口 navigator.sendBeacon('/api/firestore-update', updatePayload); });
后端代码示例(Node.js + Express)
const { initializeApp } = require('firebase-admin/app'); const { getFirestore } = require('firebase-admin/firestore'); const express = require('express'); const app = express(); // 初始化Firebase Admin initializeApp(); const db = getFirestore(); // 接收前端更新请求并同步到Firestore app.post('/api/firestore-update', express.json(), async (req, res) => { try { const { docId, ...updateData } = req.body; await db.collection('your-collection-name').doc(docId).update(updateData); res.status(200).send('更新完成'); } catch (err) { console.error('Firestore更新失败:', err); res.status(500).send('更新失败'); } }); app.listen(3000, () => console.log('后端服务运行中'));
方案二:直接调用Firestore REST API并启用keepalive
使用浏览器Fetch API的keepalive选项,直接调用Firestore的REST接口完成更新,无需自建后端。
代码示例
window.addEventListener('unload', async () => { const projectId = 'your-firebase-project-id'; const collectionId = 'your-collection-name'; const docId = 'target-doc-id'; // 按Firestore REST API格式构造更新数据 const updateData = { fields: { lastActive: { timestampValue: new Date().toISOString() } // 其他字段需遵循Firestore数据类型规范 } }; // 调用Firestore REST接口,启用keepalive保证请求完成 fetch(`https://firestore.googleapis.com/v1/projects/${projectId}/databases/(default)/documents/${collectionId}/${docId}?updateMask.fieldPaths=lastActive`, { method: 'PATCH', headers: { 'Content-Type': 'application/json', // 前端用当前用户ID Token鉴权,需确保Token有效 'Authorization': `Bearer ${await firebase.auth().currentUser.getIdToken()}` }, body: JSON.stringify(updateData), keepalive: true }).catch(err => console.error('更新失败:', err)); });
注意:前端使用ID Token鉴权时,要确保Token在窗口关闭时未过期;如果是敏感操作,优先选择方案一的后端鉴权方式。
不推荐的方案:beforeunload事件
beforeunload事件会触发确认弹窗,强制用户确认是否离开页面,严重影响体验。而且部分浏览器会限制该事件中的异步操作时长,仍存在更新失败的可能,除非你能接受弹窗体验,否则不建议使用。
内容的提问来源于stack exchange,提问作者Owenn
相关产品推荐
相关产品推荐

