从Firebase读完后返回数组

时间:2018-01-14 03:54:27

标签: javascript firebase asynchronous firebase-realtime-database

我想将满足某个条件的所有值推送到数组然后返回此数组。这是我的代码

exports.getNearbyPosts = function (myLat, myLng){
  var query = firebase.database().ref("posts/").orderByKey();
  var listOfItems = [];
  query.once("value")
    .then(function(snapshot) {
      snapshot.forEach(function(childSnapshot) {
        var key = childSnapshot.key;
        var childData = childSnapshot.val();
        var dist = getDistanceBetweenCoord(childData.lat, childData.lng, myLat, myLng);
        if(dist < 10239820938502){
          listOfItems.push(childSnapshot);
        }
    });
  });

  return listOfItems;
}

但是因为forEach是异步的,而且好像我不能在forEach上使用回调,所以我返回的listOfItems只是一个空数组。我也试过“.then”,但它只允许我在“.then”中做更多的东西,我想把这个数组作为变量返回到代码的其他部分。在执行forEach后如何返回正确的数组?

1 个答案:

答案 0 :(得分:6)

forEach不是异步(JavaScript, Node.js: is Array.forEach asynchronous?),而是query.once("value")。您可以通过各种方式解决此问题。使用回调,承诺或等待/异步。

我建议阅读这个非常有用的答案,通过更好的例子来涵盖更多内容:How do I return the response from an asynchronous call?

使用回调

这里的想法是提供一个函数,可以在完成异步工作后使用结果调用,但是在forEach中的工作完成之后。

exports.getNearbyPosts = function (myLat, myLng, callback){
  var query = firebase.database().ref("posts/").orderByKey();
  var listOfItems = [];
  query.once("value").then(function(snapshot) {
    snapshot.forEach(function(childSnapshot) {
      var key = childSnapshot.key;
      var childData = childSnapshot.val();
      var dist = getDistanceBetweenCoord(childData.lat, childData.lng, myLat, myLng);
      if(dist < 10239820938502){
        listOfItems.push(childSnapshot);
      }
    });
    callback(listOfItems)
  });
}

getNearbyPosts(0, 0, (result) => {
  console.log(result);
});

承诺(ES2016)

Promise是处理异步代码的另一种方法。我建议在这里阅读https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises。它会比我更好地解释它们。

以下是使用promises的代码:

exports.getNearbyPosts = function (myLat, myLng){
  var query = firebase.database().ref("posts/").orderByKey();
  var listOfItems = [];
  return new Promise((resolve, reject) => {
    query.once("value").then(function(snapshot) {
      snapshot.forEach(function(childSnapshot) {
        var key = childSnapshot.key;
        var childData = childSnapshot.val();
        var dist = getDistanceBetweenCoord(childData.lat, childData.lng, myLat, myLng);
        if(dist < 10239820938502){
          listOfItems.push(childSnapshot);
        }
      });
      resolve(listOfItems);
    });
  });
}

getNearbyPosts(0, 0).then(result => {
  console.log(result);
});

这实际上可以进一步简化,因为它显示query.once返回一个承诺本身。我们可以简单地返回query.once提供给我们的承诺,该承诺将在您的内部函数.then之后触发一次。我们可以将它们连在一起。

exports.getNearbyPosts = function (myLat, myLng){
  var query = firebase.database().ref("posts/").orderByKey();
  var listOfItems = [];
  
  // We return the promise created by query.once
  return query.once("value").then((snapshot) => {
  
    // our inital .then will do some data filtering
    snapshot.forEach((childSnapshot) => {
      var key = childSnapshot.key;
      var childData = childSnapshot.val();
      var dist = getDistanceBetweenCoord(childData.lat, childData.lng, myLat, myLng);
      if(dist < 10239820938502){
        listOfItems.push(childSnapshot);
      }
    });
    
    // We return here to continue the chain. The next .then that picks this up will have this result
    return listOfItems;
  });
}

// Our last promise resolution in the chain, containing listOfItems
getNearbyPosts(0, 0).then(result => {
  console.log(result);
});