簡體   English   中英

如何讓程序等到 Angular 中執行 observable

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM