Я не могу получить значение "результат" в Node.js

В моем console.log(info) я хочу получить значение "result". Но когда я использую 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. Как я могу это сделать?

Спасибо

Ответ 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

Подробнее

Для получения дополнительной информации см.:

Node поддержка

Для поддержки этого синтаксиса в версиях Node см.:

В местах, где у вас нет встроенной поддержки async и await, вы можете использовать Babel:

или со слегка отличающимся синтаксисом, основанным на генераторе, как в co или сопрограмме Bluebird:

Ответ 2

В вашем коде 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
});