【问题标题】:Promise in Angular 9Angular 9 中的承诺
【发布时间】:2020-06-03 13:19:00
【问题描述】:

我正在尝试使用 Promise 在 Angular 中编写一个同步函数调用,但它仍然得到与预期不同的结果。 我有 2 个函数使用从 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

我做错了什么?
我也尝试过使用回调,但效果总是一样的。

【问题讨论】:

  • 为什么两者都给this.price = price;赋值???这是错字吗?
  • 你想只使用 Promise 还是我们可以使用 observables 来做到这一点?
  • 您无需等待异步函数完成即可立即解决承诺。 Promise 包装器不会使它们同步
  • 如果不是3,1,2,你期待什么序列?
  • 1.事实上,我添加到表格中,我希望示例尽可能简单。 2. 我希望 then() 段在末尾@bjdose Prefer Promise。

标签: angular typescript


【解决方案1】:

如果你想使用 Promise,你可以使用 async/await 但你可以使用 rxjs 来做这件事。

可观察流

我创建了两个函数来模拟您的问题,一个称为 getDataAsObservable 代表您的 getData 方法,另一个称为 getDataAsPromise 代表您的承诺,然后我使用 concat ,它是来自 rxjs 的可观察创建方法,它顺序发出所有值从给定的 Observable 开始,然后转到下一个。

我将 first$、second$ 和 third$ 异步函数传递给 concat 和订阅,以便打印结果。

承诺流程

否则,如果使用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 here 和 rxjs here 的更多信息。

你可以查看这个here on Stackblitz的简单复制

【讨论】:

    【解决方案2】:

    你可以使用来自 rxjs 的zip

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

    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
      })
    }
    

    【讨论】:

      【解决方案3】:

      因为它们是你需要尊重它们的解决时间的承诺,这意味着要等到它们完成,这意味着当你依赖它们的结果时,你不能将它们作为正常函数调用。

      另外,因为它是一个角度应用程序,尝试通过from 函数将它们转换为 rxjs 流。

      getData1(shortcut: string): Observable<CurrentPrice> { // <- return stream
        return this.apiServ.getPrice(shortcut).pipe(
          tap(console.log, console.log), // logs emits and errors
        );
      }
      
      getData2(shortcut: string): Observable<CurrentPrice> { // <- return stream
        return this.apiServ.getPrice(shortcut).pipe(
          tap(console.log, console.log), // logs emits and errors
        );
      }
      
      data(shortcuts): Observable<[CurrentPrice, CurrentPrice]> { // <- return stream
        return combineLatest([
          this.getData1(shortcuts[0]),
          this.getData2(shortcuts[1]),
        ]);
      }
      
      ngOnInit() {
        const myPromise = new Promise((resolve, error) => {
          // wait until completed
          this.data(this.shortcuts).pipe(
            take(1), // <- in promise we need just 1 emit
          ).subscribe(prices => resolve(prices), error); 
        });
        myPromise.then((value) => {console.log(value)}); // profit
      }
      

      【讨论】:

        猜你喜欢
        • 2021-02-04
        • 2015-09-26
        • 1970-01-01
        • 2021-01-21
        • 1970-01-01
        • 2015-07-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多