[英]How to make program wait until observable is executed in Angular
我正在做一個 angular 項目,我有一種情況是使用 observable 調用后端來獲取產品。
這是代碼的樣子。
getProducts () : Product[] {
this.http.get<[]>(this.m_baseURL+'/products').subscribe(res => {
console.log(res)
this.products = res;
});
return this.products
}
問題是,return 語句不會等待上面的語句執行。 在我的組件中,我得到一個空數組。 我在服務和組件中都使用控制台日志進行了檢查。 結果是 return 語句在 observable 完成賦值之前被執行。
我如何讓它停止直到它完成它的工作,就像 async await 一樣。 我應該使用普通的 async await 而不是 observable 嗎?
這是我的第一個Angular項目,新手問題請見諒。
一些任務不是等待返回時間,而是使用反應式方法。
一些服務.ts
products$: Product[];
getProducts() : Product[] {
this.products$ = this.http.get<[]>(this.m_baseURL+'/products');
}
一些組件.ts
filteredProducts: Product[];
private readonly unsubscribe$ = new Subject();
constructor(private someService: SomeService){}
ngOnInit() {
this.someService.getProducts();
this.someService.products$.pipe(takeUntil(this.unsubscribe$)).subscribe((products) => {
this.filteredProducts = products.filter(product => product.id > 0); // look over filtering
});
}
ngOnDestroy() {
this.unsubscribe$.next();
}
SomeComponent.html
<div *ngFor="product of filteredProducs">{{ product }}</div>
解決這個常見問題的方法有很多。 還有很多方法可以改進它。 這是一種方式。 我不知道你的過濾是如何工作的,但如果可能的話我更願意使用| async
| async
pipe 完全避免手動訂閱並使用額外的 pipe 進行過濾或過濾可觀察對象本身。
您可以為此使用異步/等待模式,但我建議不要這樣做。 了解如何使用 Observables 進行異步編程。
加載產品的服務方法應該返回 Observable:
getProducts () : Observabe<Product[]> {
return this.http.get<[]>(this.m_baseURL+'/products')
}
消費代碼應該訂閱 Observable 並獲取數據:
myGetProductService.getProducts().subscribe(res => {
console.log(res)
this.products = res;
});
Angular 的處理方式是不返回Product[]
,而是返回 Observable 本身:
getProducts(): Observable<Product[]> {
return this.http.get<Product[]>(this.m_baseURL+'/products');
}
然后你使用async
pipe 訂閱這個 Observable,Angular 會自動顯示數據。
這是針對服務方法的情況。 如果您在組件中執行此操作,簡單的答案是:不要。 把它放在服務中。 這就是他們的目的。
強烈建議您嘗試 Angular 的英雄之旅教程。 他們 go 處理這類事情。
要等待可觀察對象的第一個值,您可以使用firstValueFrom()
。 這種方法很危險,因為它會導致您的應用程序無限期掛起,始終包含超時機制。
async getProducts(): Promise<Product[]> {
const res = await firstValueFrom(
this.http.get<[]>(this.m_baseURL + '/products').pipe(timeout(10000))
);
console.log(res);
this.products = res;
return this.products;
}
更好的設計是只發出 http 請求來更新this.products
,並且只使用變量,就像它總是有內容一樣,如果您希望在更新時發生副作用,您可以在訂閱中做一些其他事情。
products: Product[] = [];
ngOnInit(){
this.updateProducts();
}
updateProducts() : void {
this.http.get<[]>(this.m_baseURL+'/products').subscribe(res => {
console.log(res)
this.products = res;
this.doSomething();
this.doSomethingElse();
});
}
當收到 http 響應時,更改檢測將自動更新您的 html,但您始終可以使用ChangeDetectorRef.detectChanges()
強制執行它。
<div *ngFor="product of products">{{ product.name }}</div>
在您的第一個訂閱完成之前,上面的 html 將是空白的,此時它應該會自動更新。
如果您使用的是服務,它看起來像這樣:
服務
products: Product[] = [];
updateProducts() : void {
this.http.get<[]>(this.m_baseURL+'/products').subscribe(res => {
console.log(res)
this.products = res;
this.doSomething();
this.doSomethingElse();
});
}
成分
constructor(private service: MyService){}
ngOnInit(){
this.updateProducts();
}
get products(){
return this.service.products;
}
updateProducts(){
this.service.updateProducts();
}
這兩個包裝器方法只是為了讓您不必在 html 中編寫service
。
如果您希望在不同的組件中發生獨特的副作用,您可以將this.products
轉換為一個主題,然后您可以訂閱並在products
發生變化時執行回調。 BehaviorSubject
允許您將值初始化為空數組。
服務
products$ = new BehaviorSubject<Product[]>([]);
updateProducts() : void {
this.http.get<[]>(this.m_baseURL+'/products').subscribe(res => {
console.log(res)
this.products$.next(res);
});
}
如果您想在組件中保存主題的值而不是使用async
pipe 進行訂閱,請確保在組件被銷毀時取消訂閱。 這是因為此主題不像HttpClient
中的可觀察對象那樣完成,因此除非取消訂閱,否則訂閱將保留在 memory 中。
成分
sub = new Subscription();
products = [];
constructor(private service: MyService){}
ngOnInit(){
this.sub = this.service.products$.subscribe(res => {
console.log(res)
this.products = res;
this.doSomething();
this.doSomethingElse();
});
this.updateProducts();
}
updateProducts(){
this.service.updateProducts();
}
ngOnDestroy(){
this.sub.unsubscribe();
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.