【问题标题】:Reading nested data from Firebase returns something else than an array从 Firebase 读取嵌套数据返回的不是数组
【发布时间】:2019-04-13 21:47:00
【问题描述】:

尝试读取(并期望)这样的嵌套数组:

var array = [
0: {subArrayy: {...}, title: "Title"}, 
1: {subArray]: {...}, title: "Title"},
...

但是在阅读和(!)输出之后,结果很好。我的 Web 控制台向我显示了数组,一切似乎都很好。但是做 array.length 返回 0。任何迭代都返回 undefined。

我已经尝试使用我之前看到的 ladosh _.toArray 东西,但它完全没有任何作用。

var locations = []; // Empty array

  var ref = db.ref("locations/");
  ref.once("value", function(snapshot) {

    snapshot.forEach(function(item) {
      var itemVal = item.val();
      locations.push(itemVal); // Adding new items seems to work at first

    });

  });
  console.log(locations, locations.length);

输出:

chrome output

我希望它是可迭代的,就像我可以使用 array0 进行导航一样。

【问题讨论】:

  • 请同时显示写入数据库的代码和读取数据库的代码。现在我们必须猜测“位置”下的数据实际上是什么样的。
  • 您的 console.log 在您的异步函数 ref.once 完成之前被调用。 Chrome 最初会记录空数组,然后在该过程完成后填写缺失的部分,显然,愚蠢的是,数据长度除外。你应该把你的日志移到ref.once
  • @DougStevenson 我用这个作为我的参考link 这是读取它的代码。我在弄清楚如何将 JSON 与 Javascript 一起使用时遇到了很多麻烦,因此决定通过 Firebase 控制台手动上传我的代码。
  • 我要求您也编辑问题以显示写入数据库的代码,或者至少描述直接存在于位置下的数据结构。没有看到这一点,我们不知道阅读代码到底会收到什么。

标签: javascript arrays firebase firebase-realtime-database


【解决方案1】:

Firebase 异步读取数据,因此应用在等待网络流量时不会被阻塞。然后一旦加载数据,它就会调用你的回调函数。

您可以通过放置一些日志语句轻松地看到这一点:

console.log("Before starting to load data");
ref.once("value", function(snapshot) {
  console.log("Got data");
});
console.log("After starting to load data");

当你运行这段代码时,输​​出是:

开始加载数据之前

开始加载数据后

得到数据

这可能不是您期望的顺序,但它准确地解释了为什么您在记录时得到一个零长度数组。但是由于主要代码直接继续,到你console.log(locations, locations.length)的时候数据还没有加载,你还没有把它推到数组中。


解决方案是确保所有需要数据中数据的代码要么在回调内部,要么从那里调用。

所以这会起作用:

var locations = []; // Empty array

var ref = db.ref("locations/");
ref.once("value", function(snapshot) {

  snapshot.forEach(function(item) {
    var itemVal = item.val();
    locations.push(itemVal);
  });

  console.log(locations, locations.length);

});

这样:

function loadLocations(callback) {
  var locations = []; // Empty array

  var ref = db.ref("locations/");
  ref.once("value", function(snapshot) {
    snapshot.forEach(function(item) {
      var itemVal = item.val();
      locations.push(itemVal);
    });
    callback(locations);
  });
});

loadLocations(function(locations) {
  console.log(locations.length);
});

最后一个 sn-p 的一个更现代的变体是返回一个承诺,而不是传入一个回调。

function loadLocations() {
  return new Promise(function(resolve, reject) {
    var locations = []; // Empty array

    var ref = db.ref("locations/");
    ref.once("value", function(snapshot) {
      snapshot.forEach(function(item) {
        var itemVal = item.val();
        locations.push(itemVal);
      });
      resolve(locations);
    });
  })
});

然后你可以这样称呼它:

loadLocations().then(function(locations) {
  console.log(locations.length);
});

或者使用现代 JavaScript,您可以使用 async / await 并执行以下操作:

let locations = await loadLocations()
console.log(locations.length);

请记住,最后一个 sn-p 仍然具有相同的异步行为,并且 JavaScript 运行时(或转译器)只是对您隐藏它。

【讨论】:

    【解决方案2】:

    设置睡眠功能约 300 毫秒似乎可以解决问题。我认为这与同步有关,但并不完全确定。我想它只需要一些时间来处理查询并分配所有内容。

    【讨论】:

    • 将 console.log() 移动到回调函数中。它应该返回正确的长度。如果数据下载时间超过 300ms,添加 setTimeout 会抛出不正确的结果。
    【解决方案3】:

    在读取函数上使用 await 似乎也有帮助。

    【讨论】:

      猜你喜欢
      • 2023-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多