我正在尝试使文件包含在帖子日志中。我在这里做错了什么?当我尝试获取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
返回给您的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
该演示是您问题的简单抽象。 “不工作”版本会创建一个不返回的可观察对象地图。 “工作”版本切换到
forkJoin
并返回。在这两种情况下,保护if
块的条件都为true。优化可观察的创作
我认为可以简化内部观测值的创建并使其更安全。
当可以直接使用
combineLatest
时,将forkJoin
数组包装在forkJoin
中似乎有点多余。为了更清楚,我将数组映射与可观察的创建分开。这也将帮助您避免在以
combineLatest
或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。
我还建议创建一些接口并使用强类型。如果仅依靠良好的变量命名,您很快就会迷失方向(当然,这并不是说我们给变量取了坏名...)