JavaScript Promise结合Firebase查询时异步执行顺序异常求助
解决Firebase异步查询的Promise顺序问题
我来帮你搞定这个异步执行顺序的坑!你的问题核心在于:你在循环里发起的用户表查询(getDataToUsers.once)是异步操作,但你没等这些查询全部完成就直接调用了resolve(),导致外部的then提前执行,所以才会出现Second在terminateStatus之前打印的情况。给回调加async没用,因为Firebase根本不会处理回调的返回值,那个Promise直接被忽略了。
具体修改方案
我们需要把所有异步查询都包装成Promise,然后用Promise.all()等待它们全部完成后再resolve。同时,建议把refReview.on换成once(如果不需要实时监听数据变化的话),避免重复触发回调。
修改后的getDataFirebase函数如下:
function getDataFirebase() { return new Promise(async function(resolve, reject) { try { // 用once获取一次数据,替代on(如果不需要实时监听) const reviewSnap = await refReview.once("value"); const reviewData = reviewSnap.val(); const Collect = []; // 建议用局部变量替代全局,避免污染 const userQueryPromises = []; for (const key in reviewData) { const currentReview = reviewData[key]; // 先把评论数据存入Collect Collect.push({ "RevieweeName": `${currentReview.revieweeID.firstname} ${currentReview.revieweeID.lastname}`, "ReviewerName": `${currentReview.reviewerID.firstname} ${currentReview.reviewerID.lastname}`, rating: currentReview.rating, content: currentReview.content, keyOfReviewee: currentReview.revieweeID.userID }); // 创建用户查询的Promise,并加入数组 const userRef = firebase.database().ref("users").child(currentReview.revieweeID.userID); const userQueryPromise = userRef.once("value").then(userSnap => { const userData = userSnap.val(); const terminateStatus = userData.isTerminated; console.log("terminateStatus", terminateStatus); }); userQueryPromises.push(userQueryPromise); } // 等待所有用户查询完成后,再resolve await Promise.all(userQueryPromises); resolve(Collect); // 把Collect作为结果返回,外部可以直接接收 } catch (error) { reject(error); // 处理可能出现的错误 } }); }
对应的外部调用调整
现在你可以直接在then里拿到Collect,不用依赖全局变量:
getDataFirebase() .then(function(Collect) { console.log(Collect); console.log("first"); return getDataFirebaseUser(); }) .then(function() { console.log("Second"); }) .catch(function(error) { console.error("出错了:", error); // 别忘了处理错误 });
为什么这样改能解决问题?
- Promise化Firebase查询:Firebase的
once方法本身就支持返回Promise,不用传回调,这样我们可以用await或者.then()来等待查询完成。 - 批量等待异步操作:把所有用户查询的Promise收集到数组里,用
Promise.all()等待它们全部完成,这时候再调用resolve(),就能确保外部的then在所有异步操作结束后才执行。 - 避免全局变量污染:把
Collect改成函数内部的局部变量,通过resolve返回,代码更健壮。
这样调整后,控制台的输出顺序就会符合你的预期:Collect(array) → first → terminateStatus, 1 → Second。
内容的提问来源于stack exchange,提问作者Jennica
相关产品推荐
相关产品推荐

