给定一组键,使用firebase获取多个单独的值

时间:2017-06-07 02:19:08

标签: javascript firebase firebase-realtime-database promise

我正在尝试访问Firebase中的多个单独密钥。我正在使用基于承诺的函数和for循环来迭代给定的键。

以下是代码:

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循环完成并返回完整结果的方式重写此内容。

3 个答案:

答案 0 :(得分:2)

之前的答案是可靠的,除了返回的promise已解析为data_obj

的数组

因此,您需要做的是将循环的每次迭代更改为承诺,然后等待使用Promise.all解析所有承诺

以下是使用ES2015的方法 - 当你使用Promise时,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;
        }, {})
    );
}

它转发到旧学校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之后的.then将所有这些结果合并到一个对象,例如:{ key1: value1, key2: value2, ......

  

上面的代码使用.once('value'而不是.on('value' - 正如评论中指出的那样,使用.on会使听众附加。由于Promise只能在ONCE中解决,因此使用.once

是有意义的

答案 1 :(得分:1)

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

最小的代码更改可以是这个。基本上,而不是立即回报承诺。创建promises数组并通过Promise.all解析它。

答案 2 :(得分: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;
    }, [])
  );
}