angular - 有条件地链接多个 observables 的更简洁的方法
问题描述
我有一种方法可以更新 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
)
}
解决方案
在 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
})
}
我已经将您的代码拆分了一下,以使其更加通用和可测试。
PS为什么写this.attachments.length <= 0
可以低于0?
推荐阅读
- node.js - 如何在 Elastic Beanstalk 上启用安全 Web 套接字
- html - IE11 在网格中居中时忽略绝对项目内容宽度
- php - 如何从数据库中检索和显示图像?
- c++ - 进程中线程的最高优先级是什么?
- python - Pandas Multiindex 从索引的第一个条目中获取值
- apache-camel - 骆驼似乎忽略了 onException 指令 - 我做错了什么?
- ethernet - BeagleBone Black 表示来自笔记本电脑以太网端口的传入帧正在使用 Internet 协议版本 6
- asp.net - asp.net mvc 中的 mvc _layout 文件中的下拉列表
- python - 使用python从图像中过滤出小的网格线
- c++ - 如何使用 PushButton-Qt 连接 ComboBox 和 TextBrowser?