Reading nested data from Firebase returns something else than an array

纵然是瞬间 提交于 2020-03-05 06:04:12

问题


Trying to read (and expect) a nested array like this:

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

However after reading and (!) outputting, the result is fine. My web console shows me the array and everything seems good. BUT doing array.length returns 0. And any iteration returns undefined.

I've tried using ladosh _.toArray thing that I've seen earlier, but it does absolutely nothing.

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);

Output:

chrome output

I expected it to be iterable, in the way I could just use array0 to navigate.


回答1:


Firebase reads data asynchronously, so that the app isn't blocked while waiting for network traffic. Then once the data is loaded, it calls your callback function.

You can easily see this by placing a few log statements:

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

When you run this code the output is:

Before starting to load data

After starting to load data

Got data

This is probably not the order you expected, but it explains exactly why you get a zero length array when you log it. But since the main code continued on straight away, by the time you console.log(locations, locations.length) the data hasn't loaded yet, and you haven't pushed it to the array yet.


The solution is to ensure all code that needs data from the data is either inside the callback, or is called from there.

So this will work:

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);

});

As will this:

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);
});

A more modern variant of that last snippet is to return a promise, instead of passing in a callback.

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);
    });
  })
});

And you can then call it like this:

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

Or with modern JavaScript you can use async / await and do:

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

Just keep in mind that this last snippet still has the same asynchronous behavior, and the JavaScript runtime (or transpiler) is just hiding it from you.




回答2:


Placing a sleep function for about 300ms seems to fix the problem. I think it has something to do with syncing, though not entirely sure. It just needs some time to process the query and assign everything, I suppose.




回答3:


Using await on read functions also seems to help.



来源:https://stackoverflow.com/questions/55670143/reading-nested-data-from-firebase-returns-something-else-than-an-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!