Ответ 1
Что здесь происходит
Сначала объясним, что здесь происходит. Когда вы выполните что-то вроде этого:
var info = new Promise((resolve, reject) => {
// ...
}).then(result => {
// ...
}).catch(err => {
// ...
});
то, что заканчивается как значение переменной info
, является обещанием. Это потому, что вы начинаете с обещания, возвращаемого конструктором new Promise()
, вы вызываете его метод .then()
, который возвращает второе обещание, и в этом втором обещании вы вызываете метод .catch()
, который возвращает третье обещание - и это третье обещание это то, что сохраняется в переменной info
.
Все эти вызовы методов возвращаются непосредственно перед завершением первоначального HTTP-запроса, поэтому, когда вы достигнете следующей строки:
console.log(info);
невозможно получить доступ к значению ответа от вызова request()
, потому что оно еще не произошло (обратный вызов request()
еще не был вызван в данный момент). Переменная info
имеет обещание, которое является объектом, который вы можете использовать для регистрации обратных вызовов, которые вы хотите запустить, когда это значение в конечном итоге будет доступно. Когда вы передаете его в console.log()
, он печатает, что это обещание.
Как получить значение
Теперь, когда вы хотите напечатать значение, когда оно наконец доступно, вы можете приложить ответный вызов разрешения обещания к обещанию, которое у вас есть, например. с таким кодом:
info.then((value) => {
// you can use the value here
console.log('Value:', value);
}).catch((err) => {
// the promise got rejected
console.log('Error:', err);
});
Если вы используете относительно недавнюю версию Node (7.0+), вы можете использовать await
, если вы находитесь внутри функции, объявленной с ключевым словом async
, чтобы получить значение разрешения обещания как это:
(async function () {
let value = await info;
console.log(value);
})();
или короче:
(async () => {
console.log(await info);
})();
(Если вы уже находитесь внутри функции async
, вам не нужна оболочка (async () => { ... })();
.)
Как это работает
То, что делает ключевое слово await
, - это дает обещание от неявной функции генератора, которая передает элемент управления внешнему командованию управления coroutine, который присоединяет обработчики разрешения и отклонения, что давало обещание, и запускает генератор снова, возвращая разрешенное значение от оператора await
или повышение исключения, если обещание было отклонено. Затем генератор может продолжать использовать возвращаемое значение и перехватывать исключение, или он может позволить пузырьку исключения для внешних блоков, где он может быть пойман или преобразован в отказ от неявного обещания, возвращаемого функцией async
, если не обрабатываться путь.
Как вы можете использовать его
Это может показаться сложным, но с точки зрения вашего кода он позволяет вам делать такие вещи, как:
let value = await fun();
(где fun()
- функция, которая возвращает обещание) и имеет разрешенное значение обещания, доступного в переменной value
(реальное значение, а не обещание).
Помните, что ключевое слово await
генерирует исключение, когда рассматриваемое обещание отклоняется. Для обработки этого случая вы можете использовать блок try
/catch
:
try {
let value = await fun();
// promise got resolved, you have value here:
console.log('Value:', value);
} catch (error) {
// promise got rejected, you have error here:
console.log('Error:', error);
}
который эквивалентен этому коду без нового синтаксиса:
fun().then((value) => {
// promise got resolved, you have value here:
console.log('Value:', value);
}).catch((error) => {
// promise got rejected, you have error here:
console.log('Error:', error);
});
при этом основное отличие состоит в том, что переменная scope при await
на нескольких promises в одном блоке try
в отличие от использования обработчиков с несколькими цепочками .then()
, каждый из которых возвращает новое обещание.
Ваш код выглядел так, как будто он использовался await
, но он не
Я добавил пример того, как исправить свой код с помощью await
, потому что вы написали свой код так:
var info = new Promise(...);
// here the 'info' variable is set to a promise
было действительно:
var info = await new Promise(...);
// here the 'info' variable is set to the value
// that the promise eventually resolves to
Подробнее
Для получения дополнительной информации см.:
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await
Node поддержка
Для поддержки этого синтаксиса в версиях Node см.:
В местах, где у вас нет встроенной поддержки async
и await
, вы можете использовать Babel:
или со слегка отличающимся синтаксисом, основанным на генераторе, как в co
или сопрограмме Bluebird: