将 firebase 引用传递给函数,并获得 return 值

Pass firebase reference to function, and get return value

我正在尝试创建一个函数来检查移动的子弹是否击中了玩家。

代码简化 - shoot() 移动子弹,check_if_bullet_hit_player(bulletRef) 获取子弹参考,并检查子弹是否击中任何玩家。

这是我的代码:

function shoot(){
  // ... moving bullet code
  const bulletRef = firebase.database().ref(`bullets/${bulletKey}`);
  if(check_if_bullet_hit_player(bulletRef)){
      alert("player got hit");
      bulletRef.remove();
  }
}
function check_if_bullet_hit_player(bulletRef){
  bulletRef.once("value").then(function(snapshot) {
    //for simplicity I just return true - player got hit
    return true;
  }
}

代码未触发 alert()。看完我觉得是异步的问题,但是我怎么给函数传递参数,然后得到函数的return值。

编辑:

这是完整的 check_if_bullet_hit_player() 函数,我循环遍历玩家,并检查子弹是否 <0.5 到达玩家(如果是 - 它算作命中):

function check_if_bullet_hit_player(bulletRef){
  //bulletRef.once("value").then(function(snapshot) {
  return bulletRef.get().then(snapshot => {
    let bulletX = snapshot.val().x;
    let bulletY = snapshot.val().y;
    let shooterId = snapshot.val().shooterId;

    //loop over players
    const allPlayersRef = firebase.database().ref(`players`);
    allPlayersRef.once("value", (snapshot) => {      
      players = snapshot.val() || {};

      Object.keys(players).forEach((key) => {
          if(getDistance(players[key].x, players[key].y, bulletX, bulletY) < 0.5){

            if(players[key].id != shooterId){ //not the shooter
              return true;
            }
  // ...

确实问题出在 once() 方法是异步的。但是你也忘了在check_if_bullet_hit_player()函数中returnpromises chain

以下内容,如您在问题中所做的那样使用 then(),应该可以解决问题:

function shoot() {
    // ... moving bullet code
    const bulletRef = firebase.database().ref(`bullets/${bulletKey}`);
    check_if_bullet_hit_player(bulletRef)
        .then(result => {
            if (result)
                bulletRef.remove();
        })
}

function check_if_bullet_hit_player(bulletRef) { 
    return bulletRef.get().then(snapshot => {  // See return at the beginning, and also that we use get()
       return snapshot.exists();  // I think you should check if the snapshot exists
    });
}

请注意,shoot() 函数也是异步的。所以如果你将它与其他函数调用链接起来,你需要使用 then() (和 return 承诺链)或 async/await.


根据您的评论和问题更新进行编辑:

同样,您没有 return 承诺链。您可以按如下方式修改它,但我建议您使用 every() 方法,该方法“为数组 中存在的每个元素执行一次提供的回调函数,直到它找到回调 return 是一个虚假值 "

function check_if_bullet_hit_player(bulletRef) {
    
    let bulletX;
    let bulletY;
    let shooterId;    

    return bulletRef.get().then(snapshot => {
        bulletX = snapshot.val().x;
        bulletY = snapshot.val().y;
        shooterId = snapshot.val().shooterId;

        //loop over players
        const allPlayersRef = firebase.database().ref(`players`);
        return allPlayersRef.get();  // HERE we chain the promise
    })
        .then(allPlayersSnap => {
            players = allPlayersSnap.val() || {};
            let result = false;

            Object.keys(players).forEach((key) => {
                if (getDistance(players[key].x, players[key].y, bulletX, bulletY) < 0.5 && players[key].id != shooterId) {
                    result = true;
                }
            });
            return result;
        });

}

补充说明

好像这些函数是在前端执行的(你用的是firebase.database()...)你应该在back-end里做计算,比如通过 Cloud Function,避免恶意用户伪造结果的可能性。