Firebase实时数据库用户首次登录专属数据创建及重复写入问题解决
问题根因定位
- 异步返回逻辑失效:
checkdata内部的ref.once("value")是异步执行的操作,但原函数没有把这个操作对应的Promise向外返回。在判断条件中调用checkdata(user.uid)时,函数实际返回值为undefined,取反结果恒为true,完全跳过了“数据是否存在”的判断环节,直接触发了writeUserData的全量写入。 - 写入逻辑的固有特性:Firebase Realtime Database 的
set()方法本身就是全量覆盖节点内容的操作,只要执行就会把当前节点下的所有原有数据替换为传入的字段值,这也是你观察到“全部数据被完全重写”的直接原因。 - 不必要的性能开销:原逻辑拉取整个
users根节点的全量数据,再判断是否存在对应用路子节点,数据量大时会有明显的性能损耗。
修复后的可运行代码
因为异步操作无法直接在同步的if判断中使用,需要通过async/await或者Promise链式调用拿到异步执行的判断结果后,再执行写入逻辑,同时优化节点查询路径:
const signInBtn = document.getElementById('signinbtn'); const signOutBtn = document.getElementById('signoutbtn'); const userDetails = document.getElementById('username'); const auth = firebase.auth(); const provider = new firebase.auth.GoogleAuthProvider(); signInBtn.onclick = () => auth.signInWithPopup(provider); signOutBtn.onclick = () => auth.signOut(); function toggle(className, displayState){ const elements = document.getElementsByClassName(className) for (let i = 0; i < elements.length; i++){ elements[i].style.display = displayState; } } // 给认证状态回调加async标识,支持内部使用await等待异步操作结果 auth.onAuthStateChanged(async function(user) { if (user) { toggle('userishere', 'block'); toggle('usernothere', 'none'); userDetails.innerHTML = `Hello ${user.displayName}!` console.log(user) // 等待数据存在性的异步判断结果 const isUserExist = await checkdata(user.uid) if (!isUserExist) { writeUserData(user.uid, user.displayName, user.email, user.photoURL) } } else { toggle('userishere', 'none'); toggle('usernothere', 'block'); userDetails.innerHTML = ''; } }); function checkdata(userid){ // 直接定位到对应用户的节点,不需要拉取全量用户数据 const userNodeRef = firebase.database().ref(`users/${userid}`) // 直接return once操作的Promise,让外部可以拿到异步返回的判断结果 return userNodeRef.once("value") .then((snapshot) => snapshot.exists()); } function writeUserData(userId, name, email, imageUrl) { firebase.database().ref('users/' + userId).set({ username: name, email: email, profile_picture : imageUrl, cropdata : [] }); }
额外优化提醒
如果后续需要在用户信息更新时同步修改数据库内容,不要使用
set()做全量写入,可以改用update()方法。它只会更新传入的指定字段,不会清除未传入的其他节点内容,能避免原有业务数据被意外重置。
内容的提问来源于stack exchange,提问作者Biswanath Patra
相关产品推荐
相关产品推荐

