Firebase实时数据库嵌套读取多引用:表格无数据但日志可读
Firebase实时数据库嵌套读取后表格无法渲染问题解决
问题描述
使用JavaScript操作Firebase实时数据库时,尝试嵌套读取多个引用,控制台能正常打印数据,但页面表格无法渲染对应内容,疑惑Firebase实时数据库是否不支持嵌套读取,寻求解决方法。
相关代码(原代码)
var refEmanet = firebase.database().ref('emanet'); // Add ref of child if any refEmanet.on('value', function(snapshot) { var icerik="" var no=1; snapshot.forEach((child)=>{ if(child.val().geriVermeTarihi!=0){ dataArray[no]=child.val(); console.log(child.val().isbn); icerik+='<tr>'; icerik+='<td>'+no+'</td>'; const dbRef2 = firebase.database().ref(); dbRef2.child("kitaplar").child(child.val().kitapId).get().then((snapshot2) => { if (snapshot2.exists()) { var no1=0; if(snapshot2.key==child.val().kitapId){ console.log(snapshot2.val().kitapAdi); icerik+='<td>'+snapshot2.val().kitapAdi+'</td>'; no1++; } } else { console.log("No data available"); } }).catch((error) => { console.error(error); }); icerik+='<td>'+child.val().isbn+'</td>'; const dbRef3 = firebase.database().ref(); dbRef3.child("ogrenciler").child(child.val().ogrId).get().then((snapshot3) => { if (snapshot3.exists()) { console.log(snapshot3.val()); icerik+='<td>'+snapshot3.val().ad+' '+snapshot3.val().soyad+'</td>'; } else { console.log("No data available"); } }).catch((error) => { console.error(error); }); // icerik+='<td>'+child.val().ogrId+'</td>'; icerik+='<td>'+child.val().emanetTarihi+'</td>'; icerik+='</tr>'; no++; } }); console.log(snapshot.val()); $('#ex-table').append(icerik); });
数据截图

问题原因
Firebase实时数据库支持嵌套读取,问题出在异步操作的执行顺序上:
- 你使用的
get()方法是异步的,代码会先执行完所有同步逻辑(拼接icerik的同步部分、将icerik追加到DOM),此时嵌套的get()请求还未完成,对应的icerik+=...代码根本没机会执行。 - 控制台能打印数据是因为后续异步请求完成后触发了回调,但此时DOM已经渲染完毕,修改
icerik不会再更新页面内容。
解决方法
通过Promise.all统一处理异步请求,等待所有关联数据加载完成后再渲染表格,保证HTML拼接的完整性:
var refEmanet = firebase.database().ref('emanet'); refEmanet.on('value', function(snapshot) { // 收集所有行的异步处理Promise const rowPromises = []; let no = 1; snapshot.forEach((child) => { if (child.val().geriVermeTarihi !== 0) { const emanetData = child.val(); // 同时发起书籍和学生数据的请求,用Promise.all等待两者完成 const rowPromise = Promise.all([ firebase.database().ref(`kitaplar/${emanetData.kitapId}`).get(), firebase.database().ref(`ogrenciler/${emanetData.ogrId}`).get() ]).then(([kitapSnapshot, ogrenciSnapshot]) => { let row = `<tr>`; row += `<td>${no}</td>`; // 拼接书籍名称 if (kitapSnapshot.exists()) { row += `<td>${kitapSnapshot.val().kitapAdi}</td>`; } else { row += `<td>无书籍数据</td>`; } row += `<td>${emanetData.isbn}</td>`; // 拼接学生姓名 if (ogrenciSnapshot.exists()) { const ogrenci = ogrenciSnapshot.val(); row += `<td>${ogrenci.ad} ${ogrenci.soyad}</td>`; } else { row += `<td>无学生数据</td>`; } row += `<td>${emanetData.emanetTarihi}</td>`; row += `</tr>`; no++; return row; }).catch((error) => { console.error(error); return `<tr><td colspan="5">加载出错</td></tr>`; }); rowPromises.push(rowPromise); } }); // 等待所有行的数据都准备好后,一次性渲染到表格 Promise.all(rowPromises).then((rows) => { const icerik = rows.join(''); $('#ex-table').html(icerik); // 使用html()替换内容,避免重复追加 }); });
代码说明
- Promise.all批量处理异步请求:同时发起书籍和学生数据的请求,减少等待时间,确保所有关联数据加载完成后再生成行HTML。
- 统一渲染DOM:所有行的HTML都准备好后,一次性插入表格,避免异步操作导致的内容缺失。
- 替换而非追加:使用
html()替换表格内容,避免每次数据更新时重复追加旧内容。
内容的提问来源于stack exchange,提问作者Erdem SELVİ
相关产品推荐
相关产品推荐

