Функция subscribe
немедленно возвращает объект Subscribetion и не приостанавливает выполнение вашего кода до тех пор, пока подписанная наблюдаемая реально не выдаст значение. Subscribtion
объекты не используются для получения данных из Observable, но только для отмены подписки на Observable, на который вы ранее подписались (обратите внимание, что вам не нужно отписываться от Observables, возвращаемых HttpClient
, когда они завершаются и, следовательно, отписываются автоматически).
Вызывая return this.http.get(..).subscribe(..)
, вы возвращаете этот (вам бесполезный) объект подписки вплоть до вашей функции loadLoyaltyDetails()
, где вы регистрируете его как объект data
.
Вместо этого вы должны возвращать Observables вплоть до того момента, когда вам действительно понадобятся данные из Observable (я полагаю, это loadLoyaltyDetails()
для вас). Здесь вы подписываетесь, и в функции subscribe
вы делаете то, что вам нужно делать с объектами, испускаемыми вами Observable (в вашем случае тело ответа http).
Обычно вы устанавливаете для некоторой переменной компонента, отображаемой в вашем HTML-шаблоне, значение, генерируемое Observable. Вы можете даже отложить подписку на свой шаблон с помощью AsyncPipe и вообще не подписываться вручную.
Если вам не нужно обрабатывать полный HttpResponse, а хотите получить только тело JSON и обрабатывать ошибки, вы можете сделать что-то вроде:
localLoyaltyDetails: LoyaltyDetails;
// Note that this function returns nothing especially no Subscribtion object
loadLoyaltyDetails(): void {
// supposing this is where you need your LoyaltyDetails you subscribe here
this.loyalty.getLoyaltyDetails().subscribe(loyaltyDetails => {
// handle your loyaltyDetails here
console.log("in loadLoyaltyDetails, data =", loyaltyDetails);
this.localLoyaltyDetails = loyaltyDetails;
});
}
getLoyaltyDetails(): Observable<LoyaltyDetails> {
// We call getAsJson and specify the type we want to return, in this case
// LoyaltyDetails. The http response body we get from the server at the given url,
// in this case "/loyalty/url", has to match the specified type (LoyaltyDetails).
return this.callApi.getAsJson<LoyaltyDetails>("/loyalty/url");
}
// Don't subscribe in this function and instead return Observables up until the
// point where you actually need the data from the Observable.
// T is the type variable of the JSON object that the http get request should return.
getAsJson<T>(path: string): Observable<T> {
let opts = this.getRequestOptions();
console.log("in getAsJson, path = ", path);
return this.http.get<T>(`${environment.API_URL}${path}`, opts)
.pipe(
// you could peek into the data stream here for logging purposes
// but don't confuse this with subscribing
tap(response => console.log("in getAsJson, res = ", response)),
// handle http errors here as this is your service that uses the HttpClient
catchError(this.handleError)
);
}
// copied from the Angular documentation
private handleError(error: HttpErrorResponse) {
if (error.error instanceof ErrorEvent) {
// A client-side or network error occurred. Handle it accordingly.
console.error('An error occurred:', error.error.message);
} else {
// The backend returned an unsuccessful response code.
// The response body may contain clues as to what went wrong,
console.error(
`Backend returned code ${error.status}, ` +
`body was: ${error.error}`);
}
// return an observable with a user-facing error message
return throwError(
'Something bad happened; please try again later.');
};
Подробнее о функциях HttpClient
и handleError
можно прочитать в Angular HttpClient Docs . Вы также можете написать функцию handleError
, которая возвращает значение по умолчанию для ошибок, например, в Angular Tutorial (Http Error Handling) .
Изменить относительно вашего комментария:
Создание Observable из вашего Обещания с помощью функции defer
(генерация Observable и, следовательно, выполнение Обещания откладывается до тех пор, пока подписчик фактически не подпишется на Observable).
import { defer } from 'rxjs';
// defer takes a Promise factory function and only calls it when a subscriber subscribes
// to the Observable. We then use mergeMap to map the authToken we get from
// getLoggedInToken to the Observable we get from getAsJson.
getLoyaltyDetails(): Observable<LoyaltyDetails> {
return defer(this.login.getLoggedInToken)
.pipe(
mergeMap(authToken =>
this.callApi.getAsJson<LoyaltyDetails>(authToken, "/loyalty/details/NMC")
)
);
}
Обратите внимание, что loadLoyaltyDetails ничего не возвращает, т. Е. void
.
private details: LoyaltyDetails;
loadLoyaltyDetails(): void {
// supposing this is where you need your LoyaltyDetails you subscribe here
this.loyalty.getLoyaltyDetails().subscribe(loyaltyDetails => {
console.log("in loadLoyaltyDetails, data =", loyaltyDetails);
// set a local variable to the received LoyaltyDetails
this.details = loyaltyDetails;
});
}
Поскольку ваш loadLoyaltyDetails ничего не возвращает, вы просто вызываете функцию в тот момент, когда вам нужно, чтобы она была выполнена.
this.loader.wraps<void>(
this.loadShifts().then(() => this.loadLoyaltyDetails())
);