问题
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