【问题标题】:A more succinct way to conditionally chain multiple observables有条件地链接多个 observables 的更简洁的方法
【发布时间】:2019-06-15 13:36:52
【问题描述】:

我有一种方法可以更新 MySQL 数据库上的“请求”。此请求可以选择包含附件,在这种情况下,我需要发出额外的 HTTP 请求来更新或添加附件记录(到不同的数据库表)并上传文件。

我有一个功能方法来更新请求并可选择跳过附件 HTTP 请求,但想知道实现此目的的更简洁的方法。一般来说,我是 Angular 和 RXJS 的新手,所以 rxjs 运算符的方法和使用可能不是最优的。

基本上,我正在寻找在订阅前有条件地链接一些可选 observable 的最佳方式,或者直接跳到订阅。

我正在寻找使用 iif 的潜在解决方案,返回 Observable.empty() 和不同的 rxjs 运算符,但是当我只想完全跳过它们时,这些似乎是地图函数中的选项。

onUpdateRequest() {
    // if there are no attachments added to the request
    if (this.attachments.length <= 0) {
        this.callUpdateRequest().subscribe(() => {
            // some page and form tidy up
        });

    // there are attachments, so process the new request and then file uploads
    } else {
        this.callUpdateRequest().pipe(
            switchMap(() => {
                return of(this.attachments);
            }),
            mergeMap(attachments => {
                return attachments.map(attachment => {
                    return attachment;
                });
            }),
            mergeMap(attachment => {
              return this.attachmentsService.addAttachmentFile(attachment)
                  .pipe(map(fileData => {
                          return fileData;
                   }));
            }),
            mergeMap(fileData => {
                return this.attachmentsService.addAttachment(
                    this.requestId, fileData.fileUrl
                ).pipe(
                    map(attachments => {
                        return attachments;
                    })
                );
            }),
            takeLast(1)
        )
        .subscribe(() => {
            // some page and form tidy up
        });
    )
}

private callUpdateRequest() {
    return this.requestsService.updateRequest(
        // all the request params
    )
}

【问题讨论】:

    标签: angular rxjs angular2-observables


    【解决方案1】:

    在 RxJs 中有一个有用的运算符(也是一个静态方法)iif(),顾名思义,它的工作方式类似于 JS if/else。

    使用方式

    iif(
      () => state to check,
      o1,  // Observable to execute when statement is truthy
      o2   // Observable to execute when statement is falsy
    )
    

    还有一个defer(),你需要根据需要创建 observable(否则 JS 会先尝试编译 observable,这可能会导致一些错误,所以每次有 observable 使用的传入值时我都会使用它)。

    可以像这样使用

    iif(
      () => statmenet to check,
      defer(() => o1),
      defer(() => o2)
    )
    

    而且你的代码可能会被重写为以下方式

    getRequest(attachments) {
        return iif(
            () => attachments.length === 0,
            defer(() => this.callUpdateRequest()),
            defer(() => this.callUpdateRequest().pipe(
                switchMapTo(of(attachments)),
                mergeMap(attachments => {
                    return attachments.map(attachment => {
                        return attachment;
                    });
                }),
                mergeMap(attachment => {
                  return this.attachmentsService.addAttachmentFile(attachment)
                      .pipe(map(fileData => {
                              return fileData;
                       }));
                }),
                mergeMap(fileData => {
                    return this.attachmentsService.addAttachment(
                        this.requestId, fileData.fileUrl
                    ).pipe(
                        map(attachments => {
                            return attachments;
                        })
                    );
                }),
                takeLast(1)
            ))
        );
    }
    
    onUpdateRequest() {
       this.getRequest(this.attachments).subscribe(() => {
           // do whatever you want
       })
    }
    

    我已经对您的代码进行了一些拆分,以使其更加通用和可测试。

    附:为什么写this.attachments.length &lt;= 0可以低于0吗?

    【讨论】:

    • 正是我想要的,感谢重构提示。
    猜你喜欢
    • 2017-11-14
    • 1970-01-01
    • 1970-01-01
    • 2017-05-02
    • 1970-01-01
    • 2022-01-03
    • 2014-09-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多