Promise返回值不正确

时间:2018-02-11 15:02:15

标签: javascript promise

我正在尝试使函数返回id是否为validId。 但是,有时候,即使await isValidId(230)truevalidId也不是230。

我认为这是因为promises总是以异步方式解析。是对的吗?那我该怎么设计这个功能呢?

let validId = 230;
let isValidId = function(id){
  return new Promise(resolve => {
    //async code
    resolve(validId === id);
  });
}

if (await isValidId(230)){
  //validId is not necessary 230
}

这是一个更完整的例子。

let playerAskedToLogOut = false;
let playersOnline = ['MyUsername'];
let canPlayerUseItem = async function(player,itemId){      
  let hasItem = await Database.playerHasItem(player, itemId);
  let isStillOnline = playersOnline.includes(player);
  playerAskedToLogOut = true;  //normally called by another function
  return hasItem && isStillOnline;    
};

setInterval(() => {
  useItems();
  logOutPlayers();
}, 100);

let useItems = async function(){      
  if (await canPlayerUseItem('MyUsername', 'hammer')){
    //the player is not online anymore. Yet, await canPlayerUseItem returned true
  }
}
let logOutPlayers = function(){
  if(playerAskedToLogOut)
    playersOnline = []
}

1 个答案:

答案 0 :(得分:2)

问题中的代码存在语法错误:它在非await函数中使用async,但该函数无效。 (您已重新编辑代码以制作canPlayerUseItem async

首先:在new Promise函数中使用async没有任何意义。该功能会自动为您创建承诺。所以代码(在撰写本文时,你不断改变它)真的应该只是:

let canPlayerUseItem = async function(player,itemId){
  let hasItem = await Database.playerHasItem(player, itemId);
  let isStillOnline = playersOnline.includes(player);
  return hasItem && isStillOnline;
};

canPlayerUseItem承诺通过true解决的唯一原因是,如果hasItem恢复正常,playersOnline包含player,则{当我们执行该检查时, 之后我们等待playerHasItem ..如果您在呼叫canPlayerUserItem时播放器不在线但是< / {>在线完成playerHasItem检查后,将通过true解决。

如果你想在之前playersOnline检查,等待playerHasItem来电:

let canPlayerUseItem = async function(player,itemId){
  if (playersOnline.includes(player)) {
    return false;
  }
  return await Database.playerHasItem(player, itemId);
};

或者,如果你想检查两者(但他们可能已经脱机,那么请回到中间位置):

let canPlayerUseItem = async function(player,itemId){
  if (playersOnline.includes(player)) {
    return false;
  }
  let hasItem = await Database.playerHasItem(player, itemId);
  let isStillOnline = playersOnline.includes(player);
  return hasItem && isStillOnline;
};

通过最新的编辑,您已经建议在承诺解决后将某个播放器从在线阵列中删除。这告诉我,您在使用 canPlayerUseItem的代码中了解如何知道播放器仍然在线。

答案:你不能。您在canPlayerUseItem中执行的 Nothing 可以保护您免受此中固有的竞争条件的影响:

if (await canPlayerUseItem(player, itemId)) {
    // They player may now be offline
}

...因为玩家可以在canPlayerUseItem完成检查后但在消耗该结果的代码运行之前注销。这是异步代码的本质。以上基本上是这样的:

  1. flag = canPlayerUseItem(player, itemId)
  2. 收益直到此事件循环迭代结束
  3. if (flag) ...(此时播放器可能无法再登录)
  4. 如果你需要进行检查,你必须自己在外面异步功能:

    if (await Database.playerHasItem(player, itemId) && playersOnline.includes(player)) {
        // As of this event loop, the player is online, and had the item
        // when we checked a moment ago
    }
    

    是:

    1. flag = Database.playerHasItem(player, itemId)
    2. 产生直到此事件循环迭代结束
    3. if (flag && playersOnline.includes(player) ...