无法从 combineLatest 获取数据 - Angular
Can't get data from combineLatest - Angular
我正在尝试将文件包含在 post 的日志中。我在这里做错了什么?当我尝试 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);
})
)
Be aware that combineLatest
will not emit an initial value until each observable emits at least one value. This is the same behavior as withLatestFrom
and can be a gotcha as there will be no output and no error but one (or more) of your inner observables is likely not functioning as intended, or a subscription is late.
也许您的 API 电话之一:
this.API.getFile(file.id)
returns 出错或从未完成?
这就直来直去from the documentation here
更新:
在提到 你使用 RxJs 6 之后,你需要知道 combineLatest
需要一个数组作为参数。
所以你应该考虑改成:
return combineLatest(
logs["files"].map(
file => this.API.getFile(file.id);
),
);
你的问题
您没有 returncombineLatest
可观察到您的 switchMap
。
在 switchMap
中的 if
块中,您只是在创建一个未使用的可观察对象地图。
以一种非常简单的方式,您当前正在执行此操作:
switchMap(response =>
if (response["logs"]) {
response["logs"].map(logs => of(logs));
}
return of(response);
}
我已将您的 combine latest 简化为 of
以演示问题。当 if
条件通过时,该块将创建一个新数组,然后立即将其忽略。这意味着无论您的 if 条件如何,switchMap
将始终调用 of(response)
。您的 combineLatest
数组将 永远不会 运行.
一个解决方案
您需要 return 从您的 if
块中观察到某种类型。如果您考虑要创建的数据类型,它是一个可观察值数组。因此,为此你需要一个 forkJoin
到 运行 一个可观察对象数组和 return 一个 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
此演示是对您的问题的简单抽象。 "not working" 版本创建了一个它没有 return 的可观察对象地图。 "working" 版本切换到 forkJoin
和 return。在这两种情况下,保护 if
块的条件都为真。
优化可观察创建
我认为可以简化内部可观察对象的创建并使其更安全。
当你可以直接使用 forkJoin
时,将 combineLatest
的数组包装在 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.
我还建议创建一些接口并使用强类型。如果你仅仅依靠良好的变量命名,你很快就会迷失方向(当然,我们从来没有给变量起过坏名字……)
我正在尝试将文件包含在 post 的日志中。我在这里做错了什么?当我尝试 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);
})
)
Be aware that
combineLatest
will not emit an initial value until each observable emits at least one value. This is the same behavior aswithLatestFrom
and can be a gotcha as there will be no output and no error but one (or more) of your inner observables is likely not functioning as intended, or a subscription is late.
也许您的 API 电话之一:
this.API.getFile(file.id)
returns 出错或从未完成?
这就直来直去from the documentation here
更新:
在提到 combineLatest
需要一个数组作为参数。
所以你应该考虑改成:
return combineLatest(
logs["files"].map(
file => this.API.getFile(file.id);
),
);
你的问题
您没有 returncombineLatest
可观察到您的 switchMap
。
在 switchMap
中的 if
块中,您只是在创建一个未使用的可观察对象地图。
以一种非常简单的方式,您当前正在执行此操作:
switchMap(response =>
if (response["logs"]) {
response["logs"].map(logs => of(logs));
}
return of(response);
}
我已将您的 combine latest 简化为 of
以演示问题。当 if
条件通过时,该块将创建一个新数组,然后立即将其忽略。这意味着无论您的 if 条件如何,switchMap
将始终调用 of(response)
。您的 combineLatest
数组将 永远不会 运行.
一个解决方案
您需要 return 从您的 if
块中观察到某种类型。如果您考虑要创建的数据类型,它是一个可观察值数组。因此,为此你需要一个 forkJoin
到 运行 一个可观察对象数组和 return 一个 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
此演示是对您的问题的简单抽象。 "not working" 版本创建了一个它没有 return 的可观察对象地图。 "working" 版本切换到 forkJoin
和 return。在这两种情况下,保护 if
块的条件都为真。
优化可观察创建
我认为可以简化内部可观察对象的创建并使其更安全。
当你可以直接使用 forkJoin
时,将 combineLatest
的数组包装在 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.
我还建议创建一些接口并使用强类型。如果你仅仅依靠良好的变量命名,你很快就会迷失方向(当然,我们从来没有给变量起过坏名字……)