Мне становится сложно, когда я смешиваю обещание с подпиской и другой задачей асинхронного взаимодействия.
Это моя служба авторизации:
getCurrentUserToken(){
return new Promise((resolve,reject)=>{
firebase.auth().currentUser.getIdToken(/* forceRefresh */ true).then(function(idToken) {
resolve(idToken)
}).catch(function(error) {
reject(error)
});
})
}
Это мой сервис http:
sendEmail(email) {
return this.authService.getCurrentUserToken().then(token => {
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': 'Basic server-Password',
})
};
let data = email
data['idToken'] = token
return this.http.post(this.apiServer + 'sendEmail', data, httpOptions)
})
}
Вот как я вызываю sendEmail(email)
в компоненте:
Observable.fromPromise(this.httpService.sendEmail(element)).subscribe(
data3 => {
console.log(data3)
}, error => {
console.log(error)
}
))
Мне нужно передать currentUserToken в API, чтобы API аутентифицировал пользовательский сеанс, но оба метода getCurrentUserToken()
sendEmail()
выполняются в async, поэтому я должен использовать Promise
для передачи функции Token
to sendEmail()
и пусть функция sendEmail вызывает API для отправки электронной почты.
Без обещания я могу подписаться на http.post
следующим образом:
this.httpService.sendEmail(element).subscribe(
data3 => {
console.log(data3)
}, error => {
console.log(error)
}
))
К сожалению, я ввернул его, когда добавил в него обещание, и console.log возвращает это: Observable {_isScalar: false, source: Observable, operator: MapOperator}
Пожалуйста, сообщите, как подписаться на http.post
который размещается внутри Promise
.
Здесь серьезно не нужно усложнять ситуацию.
Здесь я буду использовать синтаксис async
/await
и для этого нам придется работать с Promise
вместо Observable
s. Хорошо, мы можем использовать метод toPromise()
для значения Observable
чтобы изменить его на Promise
Для getCurrentUserToken
getCurrentUserToken() {
return firebase.auth().currentUser.getIdToken(true);
// This will already return a Promise<string>
// So no need to do a .then and then return from there.
}
sendEmail
async sendEmail(email) {
// Since getCurrentUserToken returns a Promise<string> we can await it
const token = await this.authService.getCurrentUserToken();
// token will now have the Current User Token
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': 'Basic server-Password',
})
};
let data = email
data['idToken'] = token
return this.http.post(this.apiServer + 'sendEmail', data, httpOptions).toPromise();
// Notice how we're calling the .toPromise() method here
// to change Observable into a Promise
}
Этот код пойдет в вашем Component Method, где вы ранее this.httpService.sendEmail
. УБЕДИТЕСЬ, ЧТОБЫ ОЗНАКОМИТЬСЯ, ЧТО ФУНКЦИЯ AS async
МЫСЛЬ.
// We can only await something in a function which is declared of type async
async sendEmail() {
try {
const data = await this.httpService.sendEmail(element);
// Since sendEmail again returns a Promise, I can await it.
console.log(data);
} catch (error) {
console.log(error);
}
}
Почему бы нам не использовать Observable вместо Promises.
getCurrentUserToken() {
return new Observable(obs => {
firebase
.auth()
.currentUser.getIdToken(/* forceRefresh */ true)
.then(function(idToken) {
obs.next(idToken);
obs.complete();
})
.catch(function(error) {
obs.error(error);
});
});
}
sendEmail(email): Observable {
return new Observable(obs => {
this.authService.getCurrentUserToken().subscribe(token => {
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
Authorization: 'Basic server-Password'
})
};
let data = email;
data['idToken'] = token;
this.http
.post(this.apiServer + 'sendEmail', data, httpOptions)
.subscribe(
result => {
obs.next(result);
obs.complete();
},
error => {
obs.error();
}
);
});
});
}
// now call the service from Component like this.
this.httpService.sendEmail(element).subscribe(
data3 => {
console.log(data3)
}, error => {
console.log(error)
}
));
subscribe
внутри subscribe
- это анти-шаблон, называемый «адом обратного вызова», вы можете использовать операторы выравнивания, такие как switchMap
/ mergeMap
чтобы решить эту проблему
try catch
другим асинхронным кодом илиtry catch
является оболочкой дляawait sendEmail()
?