Синхронизация против Асинхронного
Скажем, вы планируете забрать своего друга на спортивное мероприятие. Вы не уверены, когда они хотят, чтобы вы пришли, поэтому вы звоните им по телефону и спрашиваете их. Некоторое время они думают об этом, а потом говорят вам время. Вы получили запрошенную информацию, поэтому вы кладете трубку. В терминах программирования это может быть примером синхронного кода (иногда его считают «нормальным» кодом в Node.js).
Верните себя в ту же ситуацию. Однако, когда вы звоните своему другу в этот раз, они очень заняты. Вы не хотите их беспокоить, поэтому попросите их позвонить вам позже. Ты вешаешь, а теперь ждешь. Час спустя они перезвонят и скажут время. Это мыслительный процесс асинхронного кода.
За экраном происходит гораздо больше, но для простоты я не собираюсь бомбардировать вас всей этой информацией.
Обещания
Объект Promise
представляет возможное завершение (или сбой) асинхронной операции и ее результирующее значение.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
Давайте разберем код, чтобы лучше понять проблему.
User.send()
возвращает обещание.
Promise.then()
также возвращает обещание.
Следовательно, ваш код действительно выглядит так:
var messageSent = Promise --> Promise
A Promise
находится в одном из следующих состояний:
- в ожидании : исходное состояние, не выполнено и не отклонено.
- выполнено : означает, что операция успешно завершена.
- отклонено : означает, что операция не удалась.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
Я сделал console.log
для объекта messageSent и получил это Promise { <pending> }
Несмотря на то, что вы определили переменную как Обещание, она не завершена сразу, и поэтому никакое значение не возвращается Он находится в состоянии в ожидании .
* Решения 1070 *
Итак, как нам получить результат Обещания? Мы должны ждать этого.
Сохраняя простой поток, вы можете использовать ключевое слово await
. Все, что он делает, это ждет выполнения или отклонения Обещания, прежде чем продолжить выполнение следующего кода. Рассмотрим следующий пример:
// Asynchronous context (meaning within an async function) needed to use 'await.'
var messageSent = await user.send(embed);
await messageSent.react('✅');
await messageSent.react('❎');
// Create reaction collector.
В качестве альтернативы, вы можете придерживаться then()
цепей. Обратный вызов будет вызван с возвращенным значением после выполнения Обещания. В некоторых случаях это просто. Однако обратные вызовы могут очень быстро запутаться, и область действия возвращаемых значений будет ограничена. Рассмотрим этот пример:
user.send(embed)
.then(messageSent => {
messageSent.react('✅')
.then(() => messageSent.react('❎'))
.then(() => {
// Create reaction collector.
});
});
// Keep in mind that the code here will be executed immediately after 'user.send(embed).'
Я мог исправить это, по какой-то причине он не возвращал объект сообщения, поэтому я добавил messageSent = message;
в .then
Это работает в вашем случае, потому что значение в обратном вызове then()
будет выполненным Обещанием, и вы устанавливаете переменную в возвращаемое значение. Это не лучшая идея.
Обработка ошибок
Когда обещание отклонено, это означает, что что-то пошло не так. Ошибки, возникающие из-за отклоненных обещаний, должны быть обнаружены Если это не так, вы получите предупреждение в консоли с ошибкой.
Вы можете присоединить catch()
методы, которые будут работать аналогично then()
, за исключением того, что возвращают ошибку в качестве параметра обратного вызова и вызывают только при отклонении. Рассмотрим этот короткий пример:
user.send(embed)
.then(messageSent => {...})
.catch(console.error);
Вместо того, чтобы присоединять несколько методов catch()
, вы можете использовать оператор try...catch
. Если какие-либо Обещания внутри блока try
отклонены, выполняется код внутри блока catch
. Например:
try {
const user = await bot.fetchUser('someID');
await user.send(embed);
} catch(err) {
console.error(err);
}
Ресурсы