Обещание в ожидании
Мой код:
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)
который возвращает обещание в переменную. И только потом преформует некоторые действия.
9 ответов
Обещание всегда будет регистрироваться в ожидании, пока его результаты еще не решены. Независимо от состояния обещания (решено или еще не завершено) вы должны позвонить .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) //will log results.
})
это почему?
Обещания только в прямом направлении, вы можете разрешить их только один раз, и вы можете только передать их значение их .then
или же .catch
методы
подробности
Согласно спецификации Promises/A+:
Процедура разрешения обещания - это абстрактная операция, принимающая в качестве входных данных обещание и значение, которое мы обозначаем как [[Resolve]](обещание, x). Если x является правдоподобным, он пытается заставить обещание принять состояние x при условии, что x ведет себя, по крайней мере, несколько как обещание. В противном случае он выполняет обещание со значением х.
Такое обращение с последующими объектами позволяет реализациям обещаний взаимодействовать, если они предоставляют способ, соответствующий Promises/A+, а затем метод. Это также позволяет реализациям Promises/A+ "ассимилировать" несовместимые реализации разумными методами then.
Эту спецификацию немного сложно разобрать, поэтому давайте разберемся с ней:
Правило таково, если функция в .then
обработчик возвращает значение, Promise
разрешается с этим значением. Если функция возвращает Promise
следующий пункт затем будет .then
разрешенного состояния возвращенного Promise
, Как это на самом деле работает, более подробно описано ниже:
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
функция возвращает обещание, тогда решение его обещания будет решением его следующего .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 года назад, но я столкнулся с той же проблемой, и ответ на эту проблему с 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
If that situation happens for a multiple values like an array.
[
Promise { <pending> },
Promise { <pending> },
Promise { <pending> },
Promise { <pending> },
Promise { <pending> }
]
You can use
Promise.all()
this will resolve all promises.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
then
Метод возвращает ожидающее обещание, которое может быть разрешено асинхронно с помощью возвращаемого значения обработчика результата, зарегистрированного в вызове then
или отклонен, выдав ошибку внутри вызванного обработчика.
Так зовет AuthUser
не будет внезапно входить в систему пользователя синхронно, но возвращает обещание, чьи тогда зарегистрированные обработчики будут вызваны после успешного входа (или неудачного входа). Я бы посоветовал запустить всю обработку входа в систему then
пункт обещания входа в систему. Например, используя именованные функции, чтобы выделить последовательность потока:
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);
}
Смотрите раздел MDN об обещаниях. В частности, посмотрите на тип возвращаемого значения then ().
Для входа в систему пользовательский агент должен отправить запрос на сервер и дождаться получения ответа. Поскольку полное прекращение выполнения приложения во время обхода запроса обычно приводит к плохому взаимодействию с пользователем, практически каждая функция JS, которая регистрирует вас (или выполняет любую другую форму взаимодействия с сервером), будет использовать Promise или что-то очень похожее на него., чтобы доставить результаты асинхронно.
Теперь также обратите внимание, что return
операторы всегда оцениваются в контексте функции, в которой они появляются. Итак, когда вы написали:
let AuthUser = data => {
return google
.login(data.username, data.password)
.then( token => {
return token;
});
};
заявление return token;
означало, что анонимная функция передается в then()
должен вернуть токен, а не AuthUser
Функция должна. Какие AuthUser
возврат является результатом вызова google.login(username, password).then(callback);
, который оказывается обещанием.
В конечном итоге ваш обратный звонок token => { return token; }
ничего не делает; вместо этого, ваш вклад в then()
должна быть функция, которая на самом деле обрабатывает токен в некотором роде.
Ваше обещание ожидается, завершите его
userToken.then(function(result){
console.log(result)
})
после вашего оставшегося кода. Все, что делает этот код, - это.then()
выполняет ваше обещание и фиксирует конечный результат в переменной результата и выводит результат в консоль. Имейте в виду, что вы не можете сохранить результат в глобальной переменной. Надеюсь, это объяснение поможет вам.
У меня была такая же проблема раньше, но моя ситуация была немного другой в интерфейсе. Я все равно поделюсь своим сценарием, может кому-то он пригодится.
У меня был вызов API /api/user/register
в интерфейсе с адресом электронной почты, паролем и именем пользователя в качестве тела запроса. При отправке формы (форма регистрации) вызывается функция-обработчик, которая инициирует вызов выборки для/api/user/register
. Я использовалevent.preventDefault()
в начальной строке этой функции-обработчика все остальные строки, такие как формирование тела запроса, а также вызов выборки были написаны после event.preventDefault()
. Это вернулоpending promise
.
Но когда я помещаю код формирования тела запроса над event.preventDefault()
, он вернул настоящее обещание. Как это:
event.preventDefault();
const data = {
'email': email,
'password': password
}
fetch(...)
...
вместо того:
const data = {
'email': email,
'password': password
}
event.preventDefault();
fetch(...)
...