使用firebase获取多个个别值给定一组键

问题描述:

我试图访问Firebase中的多个单独的键。我正在使用基于承诺的函数和for循环遍历给定的键。使用firebase获取多个个别值给定一组键

下面的代码:

function getFirebaseData(key_arr) 
{ 
    var ref_obj, 
     data_obj = {}; 
    return new Promise(function(resolve) 
    { 
     for(var i = 0; i < key_arr.length; i++) 
     { 
      key_str = key_arr[i]; 
      ref_obj = firebase.database().ref('path/'+key_str); 
      ref_obj.on('value', function(snapshot) 
      { 
       data_obj[key_str] = snapshot.val(); 
      }); 
     } 
     resolve(data_obj); 
    }); 
} 

然后我跑这个如下:

var key_arr = ['first_key', 'second_key', 'third_key']; 
getFirebaseData(key_arr).then(function(result){console.log(result);}); 

的问题是,结果我得到的是不是所有的三个键;我只得到一个。我猜这是因为for循环内的代码是异步的,所以resolve只给了我第一个键。

我该如何重写这种方式,以便我可以等待for循环完成并返回完整的结果。

以前的答案是实心的,除了承诺返回解析为data_obj

所以一个数组,你需要做的是循环的每次迭代改变为一个承诺,然后等待所有的承诺,以解决使用Promise.all

这里是你将如何使用ES2015做到这一点 - 因为你使用的承诺,ES2015是不是反正这样的拉伸

function getFirebaseData(key_arr) { 
    return Promise.all(key_arr.map(key_str => 
     new Promise((resolve, reject) => 
      firebase.database().ref('path/'+key_str).once('value', snapshot => 
       resolve ([key_str, snapshot.val()]) 
      ) 
     ) 
    )).then(results => 
     results.reduce((result, [key, value]) => { 
      result[key] = value; 
      return result; 
     }, {}) 
    ); 
} 

这transpiles老同学ES5为:

function getFirebaseData(key_arr) { 
    return Promise.all(key_arr.map(function (key_str) { 
     return new Promise(function (resolve, reject) { 
      return firebase.database().ref('path/' + key_str).once('value', function (snapshot) { 
       return resolve([key_str, snapshot.val()]); 
      }); 
     }); 
    })).then(function (results) { 
     return results.reduce(function (result, item) { 
      var key = item[0], 
       value = item[1]; 
      result[key] = value; 
      return result; 
     }, {}); 
    }); 
} 

每个单独的承诺现在解析为一个阵列,基本上[key, value]

Promise.all后。然后所有这些结果组合到一个单一的对象,如:{ key1: value1, key2: value2, ...

上面的代码使用.once('value'而不是.on('value' - 正如在评论中指出的那样,使用.on会使听者连接。作为承诺只能用一次解决,那么它是有道理的使用.once

+0

感谢您花时间把这些放在一起 –

+2

on()离开了听者的连接。这里不应该用'()'吗? –

+0

好点@BobSnyder –

function getFirebaseData(key_arr) 
{ 
    var ref_obj, 
     data_obj = {}, 
     promises = []; 

    for(var i = 0; i < key_arr.length; i++) 
    { 
     key_str = key_arr[i]; 
     promises.push(
      new Promise(function(resolve) 
      { 
       ref_obj = firebase.database().ref('path/'+key_str); 
       ref_obj.on('value', function(snapshot) 
       { 
        data_obj[key_str] = snapshot.val(); 
       }); 
       resolve(data_obj); 
      }) 
     ) 
    } 

    return Promise.all(promises); 
} 

最小的代码更改可以是这样的。基本上,而是为了即时的回报承诺。创建承诺数组并通过Promise.all来解决它。

+0

感谢您的支持。将看看我是否可以调整这一些。 –

上Jaromanda的精心雕琢回答这个微小的变化使得使用DataSnapshot(所有信贷为他的设计)的key属性:

function getFirebaseData(key_arr) { 
    return Promise.all(key_arr.map(key_str => 
    firebase.database().ref('path/'+key_str).once('value')) 
).then(snapshots => 
    snapshots.reduce((result, snap) => { 
     result[snap.key] = snap.val(); 
     return result; 
    }, []) 
); 
}