首页 > 解决方案 > Angular 5 可链接的 API 调用以获取巨大的对象,并将进度报告给 UI

问题描述

我正在开发 Angular 5 项目,该项目在从服务器获取巨大对象时需要快速响应。为了让应用程序运行得更快,对象[Word Document]被分解成主要组件[Word Pages]。在主要组件内部,有一个加载子组件的路由器出口[段落]。

我已经给出了一个大对象的例子,它是一个包含页面和段落的 word 文档。由于从不同系统获取这些数据的复杂性,以及这些对象的重量,我决定将这些小部分组合成名为 BCA 的主要对象。

当用户导航到 BCA/:id/home/summary 时,它将加载摘要子组件的数据。同时,在后台运行一系列 API 调用以获取构成主要 BCA 对象的其他部分 [home/date、home/load、audit/summary 等]。

用户不必等到整个对象被获取,他可以在获取对象时立即看到结果。

我面临的问题是如何触发一系列可以并行运行的 API 调用,并将其进度报告给 UI。因此用户将知道给定的选项卡或子组件已加载并准备好查看。如果用户离开,则能够取消整个链。

不确定 Observable 是否可以提供帮助,以及如何运行这个报告其状态并可以取消整个列表的链表,使用什么运算符以及是否有任何外部示例演示了相同的场景。

感谢您的帮助。

标签: angulartypescriptobservable

解决方案


通常我认为人们应该带着他们尝试过的东西来询问他们收到的错误的问题,但我将给出一个不一定是复制/粘贴的简单示例,因此您可以将其用作学习示例来实现你自己的逻辑。

这是您可以如何...

  • 发出一系列并行请求,
  • 每个都有自己的加载指示器,
  • 在模板的子组件中使用来自每个并行请求的数据,
  • 为模板中的每个请求显示一个加载指示器,
  • 如果用户离开某个组件,则取消所有挂起的请求。

我将只使用一种简单、丑陋和实用的方法来使用标志;如果你愿意,你可以让它更漂亮、更可重用。

import { Component, OnInit, OnDestroy } from '@angular/core';

import { forkJoin } from 'rxjs/observable/forkJoin';
import { finalize } from 'rxjs/operators';

import { MyService } from 'services';

export class MyComponent implements OnInit, OnDestroy {
    foo: any;
    loadingFoo: boolean = true;

    bar: any;
    loadingBar: boolean = true;

    baz: any;
    loadingBaz: boolean = true;

    constructor(private myService: MyService) {}

    ngOnInit() {
        this.sub = forkJoin([
            this.myService.getFoo().pipe(
                finalize(() => this.loadingFoo = false)
            ),
            this.myService.getBar().pipe(
                finalize(() => this.loadingBar = false)
            ),
            this.myService.getBaz().pipe(
                finalize(() => this.loadingBaz = false)
            )
        ]).subscribe((responses: any[][]) => {
            this.foo = responses[0];
            this.bar = responses[1];
            this.baz = responses[2];
        })
    }

    ngOnDestroy() {
        if (this.sub) {
            this.sub.unsubscribe();
        }
    }
}

模板看起来像这样:

<ng-container *ngIf="loadingFoo">
    <loader></loader>
</ng-container>
<ng-container *ngIf="!loadingFoo">
    <foo-component [foo]="foo"></foo-component>
</ng-container>

<ng-container *ngIf="loadingBar">
    <loader></loader>
</ng-container>
<ng-container *ngIf="!loadingBar">
    <bar-component [bar]="bar"></bar-component>
</ng-container>

<ng-container *ngIf="loadingBaz">
    <loader></loader>
</ng-container>
<ng-container *ngIf="!loadingBaz">
    <baz-component [baz]="baz"></baz-component>
</ng-container>

推荐阅读