Почему моя асинхронная функция возвращает Promise {<pending>} вместо значения?

Мой код:

let AuthUser = data => {
  return google.login(data.username, data.password).then(token => { return token } )
}

И когда я пытаюсь запустить что-то вроде этого:

let userToken = AuthUser(data)
console.log(userToken)

Я получаю:

Promise { <pending> }

Но почему?

Моя основная цель - получить токен из google.login(data.username, data.password) который возвращает обещание, в переменную. И только тогда преформируйте некоторые действия.

Ответ 1

Обещание всегда будет регистрироваться в ожидании, пока его результаты еще не разрешены. Вы должны позвонить в .then, чтобы получить обещание захватить результаты независимо от состояния обещания (решено или еще не завершено):

let AuthUser = function(data) {
  return google.login(data.username, data.password).then(token => { return token } )
}

let userToken = AuthUser(data)
console.log(userToken) // Promise { <pending> }

userToken.then(function(result) {
   console.log(result) // "Some User token"
})

Почему это?

Обещания только в прямом направлении; Вы можете решить их только один раз. Разрешенное значение Promise передается его методам .then или .catch.

Подробнее

Согласно спецификации Обещаний /A+:

Процедура разрешения обещания является абстрактной операцией, принимающей введите обещание и значение, которое мы обозначим как [[Resolve]] (обещание, Икс). Если х является правдоподобным, он пытается заставить обещание принять состояние х, в предположении, что х ведет себя по крайней мере несколько как Обещаю. В противном случае он выполняет обещание со значением х.

Такое обращение с возможными объектами позволяет реализации обещаний взаимодействовать, пока они выставляют Обещания /A+ -подобного тогда метод. Это также позволяет реализациям Promises/A+ "ассимилировать" несовместимые реализации с разумными методами then.

Эту спецификацию немного сложно разобрать, поэтому давайте разберемся с ней. Правило таково:

Если функция в обработчике .then возвращает значение, тогда Promise разрешается с этим значением. Если обработчик возвращает другой Promise, то исходный Promise разрешается с разрешенным значением цепочки Promise. Следующий обработчик .then всегда будет содержать разрешенное значение связанного обещания, возвращенного в предыдущем .then.

Как это на самом деле работает, более подробно описано ниже:

1. Возвращение функции .then будет разрешенным значением обещания.

function initPromise() {
  return new Promise(function(res, rej) {
    res("initResolve");
  })
}

initPromise()
  .then(function(result) {
    console.log(result); // "initResolve"
    return "normalReturn";
  })
  .then(function(result) {
    console.log(result); // "normalReturn"
  });

2. Если функция .then возвращает Promise, то разрешенное значение этого связанного обещания передается следующему .then.

function initPromise() {
  return new Promise(function(res, rej) {
    res("initResolve");
  })
}

initPromise()
  .then(function(result) {
    console.log(result); // "initResolve"
    return new Promise(function(resolve, reject) {
       setTimeout(function() {
          resolve("secondPromise");
       }, 1000)
    })
  })
  .then(function(result) {
    console.log(result); // "secondPromise"
  });

Ответ 2

Я знаю, что этот вопрос задавали 2 года назад, но я столкнулся с той же проблемой, и ответ на эту проблему с ES6, что вы можете просто await возвращаемых функций, например:

let AuthUser = function(data) {
  return google.login(data.username, data.password).then(token => { return token } )
}

let userToken = await AuthUser(data)
console.log(userToken) // your data

Ответ 3

then метод возвращает ожидающее обещание, которое может быть решено асинхронно возвращаемым значением результирующего обработчика, зарегистрированным в вызове then, или отвергнуто метание ошибки внутри обработчика вызывается.

Поэтому вызов AuthUser не будет неожиданно регистрировать пользователя синхронно, но возвращает обещание, чьи зарегистрированные зарегистрированные обработчики будут вызываться после того, как логин завершится успешно (или не сработает). Я бы предложил запустить обработку входа в систему с помощью предложения then. EG, используя названные функции, чтобы выделить последовательность потока:

let AuthUser = data => {   // just the login promise
  return google.login(data.username, data.password);
};

AuthUser(data).then( processLogin).catch(loginFail);

function processLogin( token) {
      // do logged in stuff:
      // enable, initiate, or do things after login
}
function loginFail( err) {
      console.log("login failed: " + err);
}

Ответ 4

См. Раздел MDN по обещаниям. В частности, посмотрите на тип возврата then().

Чтобы войти в систему, пользовательский агент должен отправить запрос на сервер и ждать ответа. Поскольку ваше приложение полностью прекращает выполнение во время запроса в оба конца, обычно делает плохой пользовательский опыт, практически каждая функция JS, которая регистрирует вас (или выполняет любые другие взаимодействия с сервером), будет использовать Promise или что-то очень похожее, для получения результатов асинхронно.

Теперь также обратите внимание, что операторы return всегда оцениваются в контексте функции, в которой они появляются. Поэтому, когда вы написали:

let AuthUser = data => {
  return google
    .login(data.username, data.password)
    .then( token => {
      return token;
    });
};

указатель return token; означало, что анонимная функция, передаваемая в then() должна возвращать токен, а не функцию AuthUser. То, AuthUser возвращает AuthUser является результатом вызова google.login(username, password).then(callback); , который является обещанием.

В конечном счете ваш token => { return token; } обратного вызова token => { return token; } token => { return token; } ничего не делает; вместо этого ваш вход в then() должен быть функцией, которая в действительности обрабатывает токен.

Ответ 5

Ваше обещание ожидает рассмотрения, завершите его до

userToken.then(function(result){
console.log(result)
})

после оставшегося кода. Все, что делает этот код, это то, что .then() выполняет ваше обещание & захватывает конечный результат в result variable & распечатать результат в консоли. Имейте в виду, вы не можете сохранить результат в глобальной переменной. Надеюсь, что это объяснение может помочь вам.