subscribe 函数会立即返回一个Subscribtion 对象,并且在订阅的 observable 实际发出值之前不会暂停代码的执行。 Subscribtion 对象不用于从 Observable 获取数据,而仅用于取消订阅您之前订阅的 Observable(请注意,您不必取消订阅由 HttpClient 返回的 Observable,因为它们已完成并因此取消订阅自动地)。
通过调用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.');
};
您可以在Angular HttpClient Docs 中阅读有关HttpClient 和handleError 函数的更多信息。您还可以编写一个handleError 函数,该函数返回一个错误的默认值,例如Angular Tutorial (Http Error Handling) 中的错误。
编辑您的评论:
使用 defer 函数从您的 Promise 生成一个 Observable(Observable 的生成以及 Promise 的执行都被推迟到订阅者实际订阅了 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())
);