从Firebase读完后返回数组

Ann*_*hou 2 javascript asynchronous firebase 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;
}
Run Code Online (Sandbox Code Playgroud)

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

Dev*_*gay 6

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

我建议阅读这个非常丰富的答案,通过更好的例子涵盖更多内容:如何从异步调用返回响应?

有回调

这里的想法是提供一个函数,可以在异步工作完成后使用结果调用,但是在我们的工作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);
});
Run Code Online (Sandbox Code Playgroud)

承诺(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);
});
Run Code Online (Sandbox Code Playgroud)

这实际上可以进一步简化,因为它似乎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);
});
Run Code Online (Sandbox Code Playgroud)