【问题标题】:Wait for multiple http requests to finish before running a function in angular在以角度运行函数之前等待多个http请求完成
【发布时间】:2019-09-15 06:20:37
【问题描述】:

我有多个从 MySQL 数据库获取 JSON 数据的 http 帖子。我想要一个函数来监听所有这些,并在它们全部返回已收到数据后运行下一段代码。

我尝试了 async with await 的多种变体,但该函数似乎没有等待 HTTP 发布完成。

例如,我有一个风险服务 risk.service.ts 来获取 riskTable:

getRiskTable(): Observable<Risk[]> {
    return this.http.get(`${this.baseUrl}/getRiskTable`).pipe(
      map((res) => {
        this.riskTable = res['data'];
        return this.riskTable;
      }),
      catchError(this.handleError));
  }

在我的仪表板上,我称之为代码:

getRiskTable():any {
    return this.riskService.getRiskTable().subscribe(
      (res: []) => {
        this.riskTable = res; // the value is correctly captured here
        return true;
      },
      (err) => {
        this.error = err;
      }
    );
  }

然后是运行多个这些函数的异步函数,理论上它应该等到所有函数完成然后记录值。但是由于某种原因,全局变量 this.riskTable 在这个函数中是未定义的。

async getAllData(){
    let riskTable = await this.getRiskTable();
    let risks = await this.getAllRisks();

    console.log(riskTable); //This returns stuff
    console.log(risks);
    console.log(this.riskTable); //This returns undefined even though it was set in getRiskTable
  }

请任何指点 - 我对角度非常陌生,而且它的复杂性让我完全难过。 2 天和 100 倍的变化让这个工作我慢慢失去了我的香蕉!

【问题讨论】:

  • 你可以考虑forkJoin,它是并行运行的(如果没有相互依赖的话),在回调中你可以对数据做任何你需要做的事情。
  • 好吧,我快速浏览了 forkJoin 的发现和示例。他们在服务中运行它以获取所有 HTTP 请求,然后返回结果。我有多个 HTTP 调用需要保持模块化。我想从各种组件中一一调用它们,因此我希望组件能够从服务访问数据并等待它们完成(并行将是理想的,但我会采取任何措施此时)。

标签: angular asynchronous listener


【解决方案1】:

首先async/await 关键字用于promise,而不是Observables。因此,您可以使用 toPromise() 将 observable 转换为 Promise,也可以使用 rxjs ForkJoin。您还需要更改方法以返回可观察对象或返回承诺,您不能对订阅做太多事情,这是您调用它时subscribe 返回的内容,这就是您现在从getRiskTable 传递的内容。

另一个问题是你没有利用类型系统,不要在任何地方使用any,因为这些错误可能在编译时被捕获,现在你必须猜测为什么它在运行时失败了困难。

import { forkJoin } from 'rxjs';
import { shareReplay } from 'rxjs/operators';

getRiskTable() : Observable<Risk[]> {
  const tableObservable = this.riskService.getRiskTable().pipe(shareReplay());
  tableObservable.subscribe((res) => this.riskTable = res, (err) => {this.error = err;});
  return tableObservable;
}

getAllData() {
  let riskTable = this.getRiskTable();
  let risks = this.getAllRisks(); // should also return some observable

  forkJoin(riskTable, risks).subscribe(_ => {
    // all observables have been completed
  });
}

请注意,我还添加了shareReplay,以确保对同一个 observable 的多次订阅不会导致对 API 端点的多次调用。一个结果在 observable 的多个订阅之间共享。

【讨论】:

  • 伊戈尔,现在是凌晨 3 点。我现在真是太高兴了,我给你写了一些小东西:我是设计师,傻,视觉,有点抱怨事情变得非常艰难感谢上帝,伊戈尔来了,给了代码爱@_@! 10/10 爱你!
  • @BrendenEngelbrecht - 很高兴你让它工作了,我希望它在早上仍然有意义(在你闭上眼睛之后):)
【解决方案2】:

您的第一个函数 getRisk 返回一个可观察对象而不是承诺,您需要执行 .toPromise() 将您的可观察对象转换为承诺。 你的第二个函数 getRiskTable 订阅了 observable,这与你的第一个函数相比非常不一致,你应该做同样的事情,因为你的第一个函数只返回一个承诺,然后你的 async await 应该工作。

或者您可以使用 forkjoin(obs1,obs2),这取决于您的兴趣,但要保持一致。

【讨论】:

    【解决方案3】:

    由于您正在使用 Angular,您应该使用 RxJS 的 forkJoin 将来自两个 api 请求方法的 observable 组合成一个单独的值 observable,并将 subscribing 的值返回给它。

    记得将forkJoin 导入到您的组件中。

    import { forkJoin } from 'rxjs';
    
    ..
    
    getAllData(){
      const riskTable = this.riskService.getRiskTable();
      const risks = this.riskService.getAllRisk();
    
      forkJoin(riskTable, risks).subscribe(response => { 
        console.log(response);
      })
    }
    

    如果您坚持将其作为 Promise 处理而不是作为 Observable 处理,您可以利用 Promise.all() 将它们作为单个 Promise 返回。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-03-04
      • 1970-01-01
      • 2019-05-19
      • 1970-01-01
      • 1970-01-01
      • 2017-08-08
      • 2020-10-20
      • 2020-06-10
      相关资源
      最近更新 更多