为何onSnapshot()最后执行?Firebase注册功能问题排查
问题分析与解决方案
问题描述
我用JavaScript实现注册功能,需要将信息上传到Firebase Firestore,完成后打印数据到控制台。预期执行流程是:
- 打印Firestore数据
- 设置localStorage项
- 弹出提示框
- 跳转至其他页面
但实际执行流程是:设置localStorage → 弹出提示框 → 跳转页面(从未打印Firestore数据)。移除跳转步骤后,流程变为:设置localStorage → 弹出提示框 → 打印Firestore数据。
另外,我还需要在上传到Firestore的数据中包含用户ID,不知道怎么获取。
原因解释
onSnapshot异步特性与页面跳转冲突:onSnapshot是Firestore的实时监听方法,首次数据获取的回调是异步执行的。你在调用onSnapshot后立刻执行window.location.href,页面会立即跳转,当前页面脚本被终止,onSnapshot的回调还没来得及执行就被中断,所以控制台看不到打印内容。- 用户ID获取失败:
你的Register函数只返回了注册成功状态,没有把创建用户后的userCredential信息返回,导致后续无法获取用户的uid。
修复步骤
1. 替换onSnapshot为getDocs
因为你只需要在数据上传完成后一次性获取Firestore数据,不需要实时监听变化,用getDocs更合适——它是基于Promise的方法,能确保数据获取完成后再执行后续操作。
2. 调整执行顺序
确保打印Firestore数据的操作完成后,再执行设置localStorage、弹出提示框和页面跳转。
3. 修改Register函数返回用户信息
在注册成功后,把userCredential.user.uid返回出来,这样后续就能获取到用户ID并写入Firestore。
完整修正代码
import { createUserWithEmailAndPassword } from 'https://www.gstatic.com/firebasejs/10.7.2/firebase-auth.js'; import { collection, getDocs, addDoc } from "https://www.gstatic.com/firebasejs/10.7.2/firebase-firestore.js"; import { auth, isArtist, firestore } from "./firebase-config.js"; isArtist(); const Register = async (auth, email, password) => { try { const userCredential = await createUserWithEmailAndPassword(auth, email, password); // 注册成功后返回用户ID和成功状态 return { isChecked: true, userId: userCredential.user.uid }; } catch (error) { return { isChecked: false, info: error.code }; } }; const RegisterPage = () => { document.getElementById("btn-register").onclick = async () => { let email = document.getElementById('email-register').value; let password = document.getElementById('password-register').value; let username = document.getElementById('username-register').value; let isArtist = localStorage.getItem("isArtist"); const registerResult = await Register(auth, email, password); if (registerResult.isChecked) { // 编译账户信息,加入用户ID const data = { dateRegistration: Date.now(), userID: registerResult.userId, email, username, isArtist, }; const colRef = collection(firestore, "accounts"); try { // 先上传数据到Firestore await addDoc(colRef, data); // 再一次性获取Firestore数据并打印 const snapshot = await getDocs(colRef); const output = []; snapshot.docs.forEach((doc) => { output.push({...doc.data()}); }); console.log(output); // 打印完成后执行后续操作 localStorage.setItem("email", email); alert("Register successful"); window.location.href = "home.html"; } catch (error) { alert(`Error uploading data to Firestore: ${error.message}`); } } else { alert(`Register fail: ${registerResult.info}`); } }; }; RegisterPage();
关键修改说明
Register函数:注册成功时返回userId,失败时返回错误码,确保后续能获取用户ID。- Firestore数据获取:用
getDocs替代onSnapshot,通过await确保数据获取完成后再执行后续步骤。 - 执行顺序:调整操作顺序为:上传数据 → 获取并打印数据 → 设置localStorage → 提示框 → 页面跳转,完全符合预期流程。
内容的提问来源于stack exchange,提问作者Lam My Ky - Kailey
相关产品推荐
相关产品推荐

