为什么通过循环向Firebase插入数据时实际插入数量随机?
问题原因
- 核心原因:Key重复覆盖:
Date.now()返回值的精度为毫秒级,JavaScript同步for循环的执行速度远快于1毫秒,会出现多次循环调用Date.now()得到完全相同时间戳的情况。你用时间戳作为History下的子节点Key,后续同Key的set操作会直接覆盖之前写入的同节点数据,最终只会保留每个毫秒区间内最后一次的写入结果,自然出现实际插入数量随机、少于预期的情况。 - 次要原因:异步操作未做等待管理:Firebase的
set()是异步网络请求,你没有对这些异步操作做完成状态监听,如果测试过程中页面提前卸载、或者环境触发请求节流,也可能出现部分请求未正常发出的情况,该场景下的问题90%以上是Key重复导致的。
修复方案
- 调整节点Key生成规则,避免重复:可以把循环变量
i拼到Key中,或者直接用Firebase SDK自带的push()方法生成全局唯一的递增Key,示例修改后的代码如下:
function sendMessage(times){ const writePromises = []; // 收集所有异步写入的Promise,方便后续统计耗时 for(let i = 0; i < times; i++){ console.log(i); let messageObj = { user: "testUser" + i, message: "message" + i }; // 方案1:拼接i避免Key重复 const ref = firebase.database().ref("History/" + Date.now() + "_" + i); // 方案2:用push生成唯一Key,更推荐 // const ref = firebase.database().ref("History").push(); writePromises.push(ref.set(messageObj)); } // 所有写入完成后再统计耗时 Promise.all(writePromises).then(() => { console.log("所有数据写入完成,可统计结束时间"); }) } window.onload = function () { sendMessage(50); }
- 如果需要准确统计插入耗时,不要从循环开始就计时,要等
Promise.all返回后再计算结束时间,否则统计的只是同步循环的执行耗时,不是真正的网络写入完成耗时。
内容的提问来源于stack exchange,提问作者Caio Peres
相关产品推荐
相关产品推荐

