Я не могу получить значение "результата" в Node.js
В моем console.log(info)
Я хочу получить значение "результат". Но когда я использую console.log(info)
, Я получил Promise { <pending> }
:
var info=new Promise((resolve, reject) => {
request(options, (err, res, body) => {
if (body.match('success') || body.match('code="25"')) {
resolve("success");
} else {
reject(body);
}
});
}).then(result => {
return result;
}).catch(err => {
console.log("error: " + err)
});
console.log(info);
Я хотел бы получить info == result
, Как мне это сделать?
Спасибо
2 ответа
Что здесь происходит
Сначала немного объяснения того, что здесь происходит. Когда вы делаете что-то вроде этого:
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
Ключевое слово делает то, что возвращает обещание из неявной функции генератора, которая передает управление внешнему управляющему коду сопрограммы, который присоединяет обработчики разрешения и отклонения к этому полученному обещанию и снова запускает генератор, либо возвращая разрешенное значение из 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);
});
с основным отличием является переменной области видимости, когда вы await
на несколько обещаний в одном 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 смотрите:
В местах, где у вас нет собственной поддержки async
а также await
Вы можете использовать Babel:
или с немного другим синтаксисом подход на основе генератора, как в co
или сопрограммы Bluebird:
В вашем коде info
это обещание. Таким образом, вы не сравниваете info
ни к чему. Чтобы получить доступ к результату в обещании, вы используете .then()
на обещание как в:
info.then(result => {
// test result here
}).catch(err => {
// handle error here
});
Кроме того, ваш .catch()
Обработчик "ест" ошибку после ее регистрации. Если вы не сбросили ошибку или не вернули отклоненное обещание от .catch()
обработчик, то ошибка считается "обработанной", и состояние обещания изменяется на выполненное.
Итак, вы можете сделать это:
let info = new Promise((resolve, reject) => {
request(options, (err, res, body) => {
if (body.match('success') || body.match('code="25"')) {
resolve("success");
} else {
reject(body);
}
});
}).catch(err => {
console.log("error: " + err);
// rethrow error so promise stays rejected
throw err;
});
info.then(result => {
// test result here
}).catch(err => {
// handle error here
});