網站搜尋

TypeScript - Angular 9 中的 Promise


我正在嘗試在 Angular 中使用 Promise 寫一個同步函數調用,但結果仍然與預期不同。我有兩個使用該服務從 API 下載數據的函數:

getData1(shortcut: string): void {
  this.apiServ.getPrice(shortcut).subscribe(
    (price: CurrentPrice) => {
      this.price = price;
      console.log(1);
    },
    error => this.error = error
  );
}

getData2(shortcut: string): void {
  this.apiServ.getPrice(shortcut).subscribe(
    (price: CurrentPrice) => {
      this.price = price;
      console.log(2);
    },
    error => this.error = error
  );
}

我正試圖在回應完成後進行下一次函數呼叫。所以:

data(shortcuts) {
  this.getData1(shortcuts[0]);
  this.getData2(shortcuts[1]);
}

ngOnInit() {
  const myPromise = new Promise((resolve) => {
    this.data(this.shortcuts);
    resolve(3)
  });
  myPromise.then((value) => {console.log(value)});
}

但是我的瀏覽器列印出這個呼叫順序:

3 
1 
2

我到底做錯了什麼?
我也嘗試過使用回呼函式,但效果總是一樣。

答案#1

如果你想使用 promises,你可以使用 async/await,但你也可以使用 rxjs 來做到這一點。

可觀察的流

我創建了兩個函數來模擬你的問題,一個叫做 getDataAsObservable,代表你的 getData 方法,另一個叫做 getDataAsPromise,代表你的 promise,然後我使用 concat,它是 rxjs 的一個可觀察對象創建方法,按順序發出給定 Observable 的所有值,然後再移到下一個。

我將第一個、第二個和第三個非同步函數傳給 concat 並訂閱,以便將結果打印出來。

Promise 流程

否則,如果你使用 async/await,你只需要等待回應。

  import { Observable, concat } from 'rxjs';
  import { delay } from 'rxjs/operators';


  async ngOnInit() {
    // first execute promise flow and wait for the response
    await this.executePromiseFlow();
    // after promise flow we can execute observable flow
    this.executeObservableFlow(); 
  }

  executePromiseFlow = async () => {
    // I use toPromise method to convert observable to a promise
    const first = await this.getDataAsObservable(1).toPromise();
    console.info('[Promise] output', first);
    const second = await this.getDataAsObservable(2).toPromise();
    console.info('[Promise] output', second);
    const third = await this.getDataAsPromise(3);
    console.info('[Promise] output', third);
  }

  executeObservableFlow = () => {
    const second$ = this.getDataAsObservable(2);
    const first$ = this.getDataAsObservable(1);
    const third$ = this.getDataAsPromise(3);

    concat(first$, second$, third$)
      .subscribe((output) => console.info('[Observable] output', output))
  }

  getDataAsObservable = (value: number) => { 
    return new Observable((observer) => {
      observer.next(value);
      observer.complete();
    }).pipe(
      delay(value * 2000), // simulate HTTP request time
    );
  }

  getDataAsPromise = (value: number) => {  
    return Promise.resolve(value);
  }

你可以在這裡閱讀更多關於 async/await 的內容,在這裡閱讀更多關於 rxjs 的內容。

你可以在 Stackblitz 這裡查看這個的簡單重現

答案#2

你可以使用 rxjs 的 zip:

import { Observable, zip } from 'rxjs'; import { tap } from 'rxjs/operators';

getData1(shortcut: string): Observable<any>  {
  return this.apiServ.getPrice(shortcut).pipe(
    tap(
      (price: CurrentPrice) => {
        this.price = price;
        console.log(1);
      }
    )
  );
}

getData2(shortcut: string): Observable<any>  {
  return this.apiServ.getPrice(shortcut).pipe(
    tap(
      (price: CurrentPrice) => {
        this.price = price;
        console.log(2);
      }
    )
  );
}


data(shortcuts) : Observable<any> {
  const res1 = this.getData1(shortcuts[0]);
  const res2 = this.getData2(shortcuts[1]);
  return zip(res1, res2);
}

ngOnInit() {
  this.data(this.shortcuts).subscribe(() => {
    // your code
  })
}