不一致。js等待反应一条又一条消息链接的承诺。反应收集承诺未解决时的反应 [英] Discord.js awaitReaction chained promise after message.react collect the reaction as promise isn't resolved

查看:9
本文介绍了不一致。js等待反应一条又一条消息链接的承诺。反应收集承诺未解决时的反应的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用message.react函数和awaitReactions函数,我注意到了一些困扰我的事情。

我正在尝试确定应该为以下方法使用收集器还是client.on('messageReactionAdd')(这是另一个问题):

  1. 发送消息
  2. 添加反应
  3. 每次添加反应时执行某项操作(持续X秒)

所以我从一个简单的例子开始,用一个过滤器,每次都会返回true,我注意到收集器正在收集我的机器人添加到消息中的最后一个表情符号。以下是代码

const emojiNext = '➡';
const emojiPrevious = '⬅';
const emojiClap = '👏';

function filter(reaction) {
  console.log('reacted to: ', reaction.emoji.name);
  return true;
}
function sleep(ms, a){
  return new Promise(resolve=>{
    setTimeout(resolve,ms);
  }).then(d => a);
}

function sendList(channel){
  channel.send('foo')
  .then(msg => {
    console.log('First');
    return msg.react(emojiPrevious);
  })
  .then(msgReaction => {
    console.log('Second', msgReaction.message.reactions.keys());
    return msgReaction.message.react(emojiNext);
  })
  .then(msgReaction => {
    console.log('Third', msgReaction.message.reactions.keys());
    return msgReaction.message.react(emojiClap);
  })
  // .then(msgReaction =>{
  //   return sleep(100, msgReaction);
  // })
  .then(msgReaction => {
    console.log('Fourth',  msgReaction.message.reactions.keys());
    msgReaction.message.awaitReactions(filter, {max: 2, time: 1000, errors: ['time']})
    .then(collected => {
      console.log('ending', collected);
    })
    .catch(collected => {
      console.log(`After 5 sec, only ${collected.size} out of 2 reacted: ${collected.map((v,k) => k)}`);
    });
  });
}

调试

由于我尝试了一些调试,因此此示例比我的第一个示例开发了一些。

该示例发送一条消息,附加链接的Promise 3表情符号,然后开始收集表情符号。 然而,正如下面的日志所示,最后一个emoji表情被收集了(我自己从来没有按过任何emoji表情符号,我一个人在我的服务器上):

First
Second [Map Iterator] { '⬅' }
Third [Map Iterator] { '⬅', '➡' }
Fourth [Map Iterator] { '⬅', '➡', '👏' }
reacted to:  👏
After 5 sec, only 1 out of 2 reacted: 👏

有时(视情况而定)它工作正常,日志如下:

First
Second [Map Iterator] { '⬅' }
Third [Map Iterator] { '⬅', '➡' }
Fourth [Map Iterator] { '⬅', '➡', '👏' }
After 5 sec, only 0 out of 2 reacted: 

我最后是在火车上测试,网络不规则可能是原因。

所以我尝试了其他方法,我添加了睡眠函数,该函数接受毫秒数和一个值,并返回一个承诺,该函数将在毫秒数过后返回解析后的值。(取消对第3行的注释以进行此调试)。 这样,收集者永远不会收集最后一个表情符号。

我还尝试使用收集器(let res = await channel.send...)在then之前返回承诺,然后执行其余代码。我还收集了最后一个表情符号。

我知道我可以使用我的过滤器忽略机器人或我的表情符号,只关注用户的机器人(参见下面的代码),但我想知道是什么导致了这种行为。是不是我做错了什么?我对承诺有什么不理解的地方吗?

function filter(reaction, user) {
  if(user.id === client.user.id) { return false; } // or user.bot to ignore all bot
  console.log('reacted to: ', reaction.emoji.name);
  return true;
}

在我看来,在调试中看到收集器在记录所有事情之后做出反应后,我认为正在解析的承诺和将信息发送到收集器/回调的不一致是不同的,但这只是一种猜测

注意:
Node.js版本:v11.15.0
Discord.js版本:v11.5.1

推荐答案

这是因为rest API网关在与Discord交互时是分开的。

在后台,message.react会导致discord.js向discorde的REST API发起请求-discorde会收到该请求并进行处理,并返回响应,这会导致message.react返回的承诺要么解析要么拒绝。

但是,当您监听反应时,它根本没有监听REST API,而是监听网关事件-这些事件在很大程度上会导致client.on('messageReactionAdd')这样的事件在客户端发出。

当您收到来自Discorde的响应,表示您的反应已成功发布时,Discorde还没有完成向所有客户端(包括您的机器人)发送您的反应的messageReactionAdd事件!它可能有,但它可能没有。然而,在收到API响应后,您立即开始监听来自网关的反应。这就是所谓的争用条件-Discorde负责REST API的服务器与负责网关的服务器正在竞争,看谁会首先将这条信息发送给您的机器人。

这不是您可以合理避免的事情,因为您完全无法知道Gateway何时会赶上事件并向您的机器人发送自己的反应-所以您在这里应该做的是在您的筛选器中说明竞争条件,正如您在问题中所承认的那样。另一种解决方案可能涉及添加反应事件侦听器,并在侦听器检测到您的机器人的反应已经通过网关后才开始侦听新的反应,但对于这种特定情况来说,这就不那么干净了。


顺便提一句,我强烈建议使用async/await,而不是那些难看且无法阅读的承诺链。您的代码可以简化为:

async function sendList(channel){
  let msg = await channel.send('foo');
  console.log('First');
  let msgReaction = await msg.react(emojiPrevious);
  console.log('Second', msgReaction.message.reactions.keys());
  msgReaction = await msg.react(emojiNext);
  console.log('Third', msgReaction.message.reactions.keys());
  msgReaction = await msg.react(emojiClap);
  console.log('Fourth',  msgReaction.message.reactions.keys());
  try {
    let collected = await msgReaction.message.awaitReactions(filter, {max: 2, time: 1000, errors: ['time']})
    console.log('ending', collected);
  } catch(partialCollection) {
    console.log(`After 5 sec, only ${partialCollection.size} out of 2 reacted: ${partialCollection.map((v,k) => k)}`);
  }
}

应该与您当前的代码完全相同,但在我看来可读性好得令人难以置信。

这篇关于不一致。js等待反应一条又一条消息链接的承诺。反应收集承诺未解决时的反应的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆