在Angular2中加载慢速子资源

时间:2016-11-24 14:13:11

标签: angular rxjs angular2-services

Angular2组件显示一些对象。除了基础对象信息之外,还需要通过返回Observable的服务加载额外的数据并且速度很慢。

对象信息的基础部分应立即显示,并且额外数据一旦可用。

这样的事情:

SomeObjectComponent {

    someObject: SomeObject;
    extraData: ExtraData;

    @Input()
    set item(v: SomeObject) {
        this.someObject = v;
        backendService.getExtraData(v.id)
            .subscribe(d => this.extraData = d);
    }        

}

// in the template
<some-object [item]="currentlySelected"></some-object>

当加载速度很慢且用户在SomeObject的不同值之间导航时,异步加载可能会加载并为当前项目分配错误的extraData

解决这个问题的最佳方法是什么?如果每次都需要加载多个额外的数据项(并且每次加载时都会出现),该怎么办?

1 个答案:

答案 0 :(得分:1)

如果我理解正确的话,基本上你要找的是一种取消“旧的”休息电话的方法,只要选择了新项目 - &gt; rxjs-way将使用.takeUntil(...)

SomeObjectComponent implements OnDestroy {
    // to clean up any open subscriptions it is helpful to have a destroy-event
    private destroyed$: Subject<any> = new Subject<any>();

    // your vars
    someObject: SomeObject;
    extraData: ExtraData;

    @Input()
    set item(v: SomeObject) {
        this.someObject = v;
        this.loadExtraData$.next(v.id);
    }        

    // a trigger to load extra data
    private loadExtraData$: Subject<number> = new Subject<number>();  // type "number" is just an assumption, this can be whatever type "v.id" is

    // the stream to load extra data
    private extraData$: Observable<any> = this.loadExtraData$
        .takeUntil(this.destroyed$) // when the component is destroyed this will ensure that any open subscription will be closed as well to prevent memory leaks
        .switchMap(id => {
            return this.backendService
                .getExtraData(id)
                .takeUntil(this.loadExtraData$);  // will discard the rest-call the next time loadExtraData$ is triggered (if it is still running)
        })
        .do(extraData => this.extraData = extraData) // if you only need the data in the template, then don't use this line and use the "| async"-pipe instead
        .share();

    // this is called by the angular2-lifecycle, when the component is removed
    ngOnDestroy() {
        this.destroyed$.next();
    }
}

如果您只需要模板中的额外数据,那么您可能想要使用async - pipe:

<span>Some extra data: {{(extraData$ | async)?.someAttribute}}</span>

作为一个小小的侧面说明并稍微偏离主题:加载组件中的额外数据,但在组件外部并使用@Input()是更好的做法对于额外数据,原因有很多:

  • 如果组件被封装且不依赖于任何服务或其他组件,则可测试性更高效且更容易实现
  • 特别是对于休息呼叫,如果组件被添加两次,则存在发出冗余请求的危险,例如
  • 如果组件只有@Input()@Output() s ,则组件在不同的上下文中更容易重用

话虽如此,在不了解您当前的架构的情况下,这可能会带来更大的重构,这可能不值得花时间,但这是未来应用需要考虑的事项。