javascript - 无法从 combineLatest 获取数据 - Angular
问题描述
我正在尝试获取包含在帖子日志中的文件。我在这里做错了什么?当我试图pipe
得到combineLatest
. 整个代码用于数据解析服务。
return this.API.getPost(route.params.id).pipe(
switchMap((response: any) => {
if (response["logs"]) {
response["logs"].map(logs => {
if (logs["files"]) {
return combineLatest(
...logs["files"].map(file=>
this.API.getFile(file.id)
)
).pipe(
// Not getting any files from this.API.getFile(file.id)
map(files =>
files.map(file => ({
url: this.sanitizer.bypassSecurityTrustResourceUrl(
window.URL.createObjectURL(file)
)
}))
)
),
map(files => {
logs["files"] = files;
return response;
});
}
});
}
return of(response);
})
)
解决方案
你的问题
您不会将combineLatest
observable 返回给您的switchMap
.
在您的if
块中switchMap
,您只是在创建一个未使用的可观察对象映射。
以一种非常简化的方式,您当前正在执行以下操作:
switchMap(response =>
if (response["logs"]) {
response["logs"].map(logs => of(logs));
}
return of(response);
}
我已将您的最新组合简化为一个of
来演示问题。当if
条件通过时,该块将创建一个新数组,然后立即将其忽略。这意味着无论您的 if 条件如何,switchMap
都将始终调用of(response)
. 您的combineLatest
阵列将永远不会运行。
一个解法
if
你需要从你的块中返回某种可观察的。如果您考虑您正在创建的数据类型,它是一个可观察的数组。因此,为此您需要forkJoin
运行一个可观察对象数组并返回一个switchMap
可以切换到的可观察对象。
return this.API.getPost(this.route.params.id).pipe(
switchMap((response: any) => {
if (response["logs"]) {
return forkJoin(response["logs"].map(logs => {
if (logs["files"]) {
return combineLatest(
...logs["files"].map(file=>
this.API.getFile(file.id)
)
).pipe(
map(files =>
files.map(file => ({
url: this.sanitizer.bypassSecurityTrustResourceUrl(
window.URL.createObjectURL(file)
)
}))
)
),
// Not sure what this is???
map(files => {
logs["files"] = files;
return response;
});
}
}));
}
return of(response);
})
)
此外,我不确定map
我评论的目的是什么 - 它目前没有任何用途,甚至可能导致编译问题。
演示:https ://stackblitz.com/edit/angular-5jgk9z
这个演示是对您的问题的简单抽象。“不工作”版本会创建一个不返回的可观察对象映射。“工作”版本切换到 aforkJoin
并返回它。在这两种情况下,保护if
块的条件都为真。
优化可观察的创建
我认为内部可观察对象的创建可以简化并变得更安全。
当您可以直接使用时,将数组包装combineLatest
在 a 中似乎有点多余。forkJoin
forkJoin
为了更清楚,我会将数组映射与可观察的创建分开。这也将帮助您避免最终将空数组放入combineLatest
or的错误forkJoin
。
// inside the "if" block
// flatten files
const files = response["logs"]
.filter(log => !!log.files)
.map(log => log.files)
.flat();
if (files.length > 0) {
const observables = files.map(file => this.API.getFile(file.id));
return forkJoin(observables).pipe(
map(files => {
files.map(file => ({
url: this.sanitizer.bypassSecurityTrustResourceUrl(
window.URL.createObjectURL(file)
)
}))
})
);
}
这使用了.flat()
数组函数,该函数采用多维数组,例如:
[
[1,2,3],
[4,5,6]
]
并将其展平为:
[ 1,2,3,4,5,6 ]
如果您需要 IE 支持并且没有 polyfill,您可以使用此处的替代方法:https ://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat 。
我还建议创建一些接口并使用强类型。如果你仅仅依赖于好的变量命名,你很快就会迷失方向(当然,我们从来没有给变量起过坏的名字……)
推荐阅读
- cpu-architecture - 空间局部性未命中数
- xcode - Xcode 12.5 部署:上传到 App Store 时出错
- python - Pip install 与软件包的开发版本不匹配
- javascript - 使用导入模块的命名别名不适用于导出名称的点表示法?
- jquery - 如何更改 window.open() (wordpress) 的大小?
- python - Python 不创建 .txt 文件
- mysql - 错误:您的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册以获取正确的语法
- reactjs - NextJS 页面在生产中加载后暂时没有样式
- css - 引导标头不会更改图像大小
- javascript - 您如何显示来自 newsapi 的所有图像?