【问题标题】:Checking if an array of Observables have completed in a synchronous way?检查一组 Observables 是否以同步方式完成?
【发布时间】:2018-06-25 20:52:17
【问题描述】:

在我的应用程序中,如果我的表单中的任何数据尚未完成加载,我希望“保存”按钮不执行任何操作。我表单中的数据源都是Observables:source1$source2$

由于用户可以随时单击该按钮,因此我希望能够检查是否有任何 Web API 请求处于待处理状态,如果它们不执行任何操作 -- 否则保存。

我在想象这样的事情:

saveButton_onClicked() {
    if (// source1$ and source2$ are completed) {
        this.saveForm();
    }
}

在任何时候,这些可观察对象中的任何一个都可以分配给新的可观察对象(例如,当数据刷新时),我不认为 forkJoin 可以在这里工作,因为我需要真正了解 时间是否应该保存表单,我不希望点击事件等待forkJoin observable 解决。

有什么想法吗?

【问题讨论】:

    标签: angular rxjs reactive-programming


    【解决方案1】:

    实际上,我认为最简单的方法是使用 forkJoinfinalize 运算符,而不是检查源 Observables 本身,而是创建一个属性,例如。 loading,您可以随时查看是否有待处理的 Observables:

    whatever() {
      this.loading = true;
    
      forkJoin(source1$, source2$)
        .pipe(
          finalize(() => this.loading = false)
        )
        .subscribe();
    }
    
    saveButton_onClicked() {
      if (!this.loading) {
        ...
      }
    }
    

    【讨论】:

    • 每次我将source1$source2$ 分配给新的Observable 时,我是否需要销毁旧的forkJoin 并创建一个新的Observable
    【解决方案2】:

    嗯,给猫剥皮的方法有很多。 有些比其他的更优雅。我更喜欢将额外的可观察属性的数量保持在最低限度,在这种情况下似乎是 2。我会添加一个属性isRunningRequest$,其发出的值是一个标志,如果当前正在运行操作,则为 true。该标志将通过对另一个可观察对象asyncAction$ 的聚合来补充,用于跟踪当前正在运行的操作:

    export class AsyncActionData {
      actionType: 'start' | 'end';
      actionToken: string;
    }
    
        public asyncAction$ = new Subject<AsyncActionData>();
    
        public isRunningRequest$ = new BehaviorSubject<boolean>(false);
    
        constructor(...) {
            this.asyncAction$
                .pipe(
                    // we keep an array of currently running actions, and add
                    // or remove from the array according to the action type
                    scan((arr: string[], action: AsyncActionData) => {
                        return action.actionType === 'start'
                            ? arr.concat(action.actionToken)
                            : arr.filter(action => action !== action.actionToken);
                    }, []),
                    map(arr => arr.length === 0 ? false : true)
                )
                .subscribe(requestsAreRunning => this.isRunningRequest$.next(requestsAreRunning));
        }
    

    当您执行操作时,您会在asyncAction$ 上发出事件:

    this.asyncAction$.next({actionType: 'start', actionToken: 'action1'});
    this.http.post(...)
       .subscribe(result => ...,
                  null,
                  () => this.asyncAction$.next({actionType: 'end', actionToken: 'action1'})
       );
    

    (所有代码未经测试,但想法应该是合理的)

    有关 scan 运算符的文档,请参阅 herehere

    【讨论】:

    • “我更喜欢将额外的 observable 的数量保持在最低限度,所以我会使用额外的 observable” 我喜欢你的幽默:D
    • :P 与 RxJs 的解决方案总是添加一些转换后的 observable ;) 不过要改写。
    • 如果我使用这个解决方案,检查是否有待处理的操作的代码会是什么样子?
    • 你可以在“isRunningRequest$ | async” 或订阅 isRunningRequest$ 以在有请求时获取 true,在没有请求时获取 false。不过,不要使用你不理解的代码;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-26
    • 2019-03-21
    • 1970-01-01
    相关资源
    最近更新 更多