首页 文章

循环不等待promise的解析(包含嵌套的firebase调用)

提问于
浏览
0

我正在尝试在循环和外部firebase调用内部进行Firebase数据库调用 . 内部Firebase数据库调用使用从外部firebase调用和循环返回的数据,这就是它在外部运行的原因 . 然后应该将结果设置为状态 .

Problem 未在状态中设置内部Firebase数据库调用中检索的值 .

Theory 由于Firebase数据库调用是异步的,我猜测内部Firebase数据库调用在循环完成并设置状态之前没有完成 . 因此,我为内部Firebase数据库调用创建了一个承诺,以便循环将等待调用完成,然后再转到下一个项目 . 但是,检索的值仍未设置 .

有谁知道为什么循环不等待包含对Firebase数据库的调用的承诺?

MY ATTEMPT

userRef.on("value", function(snapshot) {
  var snap = [];
  // loop through each branch received from firebase
  snapshot.forEach(function(data) {
    var firstThingsFirst = data.val().firstThingsFirst;
    var someID = data.val().someID;
    var myPromise = new Promise(function(resolve, reject) {
      userRef.child('somechild').child(someID).once('value').then(function(newSnapshot) {
        console.log("newSnapshot = (below)");
        console.log(newSnapshot.val());
        resolve(newSnapshot.val());
      }, function(error) {
        // Something went wrong.
        console.error("error (below)");
        console.error(error);
        reject("noValueFound")
      });
    });
    var someValue = "";
    myPromise.then(function(valueRetrieved) {
      console.log(".then of promise is running...");
      console.log("valueRetrieved = (below)");
      console.log(valueRetrieved);
      someValue = this.checkUndefined(valueRetrieved);
    }.bind(this));
    var array = {"firstThingsFirst": firstThingsFirst, "someValue": someValue};
    snap.push(array);
  });
  this.setState({
    snapshots: snap
  });
}.bind(this));

Alternative Attempt:

userRef.on("value", function(snapshot) {
  var snap = [];
  // loop through each branch received from firebase
  snapshot.forEach(function(data) {
    var firstThingsFirst = data.val().firstThingsFirst;
    var someID = data.val().someID;
    var someValue = this.fetchValueByID(someID);

    var array = {"firstThingsFirst": firstThingsFirst, "someValue": someValue};
    snap.push(array);
  });
  this.setState({
    snapshots: snap
  });
}.bind(this));

fetchValueByID(someID) {
  userProfileRef.child('someChild').child(someID).once('value').then(function(snapshot) {
    console.log("snapshot (fetchValueByID) = (below)");
    console.log(snapshot.val());
    return snapshot.val();
  })
}

我也尝试过Firebase推荐的方法:

提前致谢 .

1 回答

  • 3

    有谁知道为什么循环不等待包含对Firebase数据库的调用的承诺?

    这样做的原因是在完成所有提取后需要调用 setState . 但是,你的代码没有做任何等待的事情 . 你只需继续循环,一旦完成,调用 setState . 你真的不知道你的提取是否完成 . 你需要一种方法来等待所有的提取 . 简而言之,由于同步和异步代码的混合存在问题 .

    你可以试试这个 . 我的想法是将所有 fetchValueByID (我在开头添加了一个 return )调用映射到一个promises数组,然后在执行 setState 之前等待所有这些调用(使用Promise.all

    userRef.on("value", function(snapshot) {
      // loop through each branch received from firebase
      // AND map to array of promises
      var promises = [];
      snapshot.forEach(function(data) {
        var firstThingsFirst = data.val().firstThingsFirst;
        var someID = data.val().someID;
        promises.push(this.fetchValueByID(someID).then(function(someValue) {
          return {
            "firstThingsFirst": firstThingsFirst,
            "someValue": someValue
          };
        }));
      });
    
      // Wait for all promises to resolve
      Promise.all(promises).then(function(results) {
        this.setState({
          snapshots: results
        });
      }.bind(this))
    
    }.bind(this));
    
    fetchValueByID(someID) {
      // Notice the return here
      return userProfileRef.child('someChild').child(someID).once('value').then(function(snapshot) {
        console.log("snapshot (fetchValueByID) = (below)");
        console.log(snapshot.val());
        return snapshot.val();
      })
    }
    

    我伪造了所有可能的数据,并将我的解决方案转换为下面简单易懂的代码段

    var promises = [];
    // Faking the snapshot
    [{
      a: 1,
      b: 10
    }, {
      a: 2,
      b: 20
    }].forEach(function(data) {
      var firstThingsFirst = data.a
      var someID = data.b
      promises.push(fetchValueByID(someID).then(function(someValue) {
        return {
          "firstThingsFirst": firstThingsFirst,
          "someValue": someValue
        };
      }));
    });
    
    // Wait for all promises to resolve
    Promise.all(promises).then(function(results) {
      console.log(results);
    });
    
    function fetchValueByID(someID) {
      // Dummy Promise resolution
      // Notice the return here
      return new Promise(function(resolve, reject) {
        setTimeout(function() {
          // Dummy manipulation
          resolve(someID * 100);
        });
      }).then(function(snapshot) {
        console.log("snapshot (fetchValueByID) = (below)");
        console.log(snapshot);
        return snapshot;
      })
    }
    

相关问题