简体   繁体   English

错误的Promise返回值

[英]Incorrect Promise return value

I'm trying to make a function returns whether an id is the validId. 我试图使函数返回id是否为validId。 However, it turns out that sometimes, even if await isValidId(230) is true , validId is not 230. 但是,事实证明,有时即使await isValidId(230)truevalidId也不为230。

I assume this is because promises are always resolved asynchronously. 我认为这是因为承诺总是异步解决的。 Is that right? 那正确吗? How am I supposed to design this function then? 那我应该如何设计这个功能呢?

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
}

Here's a more complete example. 这是一个更完整的示例。

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 = []
}

The code in the question has a syntax error: It's using await in a non- async function, which doesn't work. 问题中的代码存在语法错误:它在非async函数中使用了await ,这是行不通的。 (You've edited the code again to make canPlayerUseItem async ) (您再次编辑了代码以使canPlayerUseItem async

First: There's no purpose at all in using new Promise within an async function. 第一:在async函数中使用new Promise根本没有任何目的。 The function creates a promise for you automatically. 该功能自动为您创建一个承诺。 So that code (as of this writing, you keep changing it) really should be just: 因此该代码(在撰写本文时,您一直在对其进行更改)实际上应该是这样的:

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

The only reason canPlayerUseItem 's promise would resolve with true would be if hasItem comes back truthy and playersOnline contains player as of when we do that check, which is after we've waited for playerHasItem .. If the player is not online when you call canPlayerUserItem but is online when the playerHasItem check has completed, it will resolve with true . canPlayerUseItem会按true解析的唯一原因是,如果hasItem返回真实值,并且playersOnline包含我们执行该检查时的player ,即我们等待playerHasItemcanPlayerUserItem在线playerHasItem检查已经完成,它会与解决true

If you want to do the playersOnline check before waiting for the playerHasItem call: 如果要等待playerHasItem调用之前进行playersOnline检查:

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

Or if you want to check both (but they could have gone offline, then come back online, in-between): 或者,如果您想同时检查两者 (但它们可能已经脱机,则可以在两者之间重新联机):

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

With your latest edit, you've suggested that something is removing the player from the online array after the promise resolution. 在您的最新编辑中,您建议解决承诺后将某些东西从在线阵列中删除。 That suggests to me that you're asking about how you can know the player is still online in the code using canPlayerUseItem . 这向我暗示您正在询问如何使用 canPlayerUseItem在代码中知道播放器仍处于在线canPlayerUseItem

Answer: You can't. 答:不能。 Nothing you do in canPlayerUseItem can protect you from the race condition inherent in this: 您在canPlayerUseItemcanPlayerUseItem 任何事情canPlayerUseItem不能保护您免受此内在的竞争条件的影响:

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

...because it's possible for the player to sign out after canPlayerUseItem has done its check but before your code consuming that result runs. ...因为播放器有可能在canPlayerUseItem完成检查之后但在消耗该结果的代码运行之前退出。 This is the nature of asynchronous code. 这就是异步代码的本质。 The above is basically this: 上面基本上是这样的:

  1. flag = canPlayerUseItem(player, itemId)
  2. Yield until end of this event loop iteration 在此事件循环迭代结束之前的收益
  3. if (flag) ... (at which point the player may no longer be logged in) if (flag) ... (此时玩家可能不再登录)

If you need to do that check, you'll have to do it yourself outside the asynchronous function: 如果需要进行检查,则必须在异步函数之外自己进行检查:

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
}

which is: 这是:

  1. flag = Database.playerHasItem(player, itemId)
  2. Yield until the end of this event loop iteration 在此事件循环迭代结束之前的收益
  3. if (flag && playersOnline.includes(player) ... if (flag && playersOnline.includes(player) ...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM