我使用RxJS在Angular中有一个复杂的可观察链,我遇到了嵌套的switchMap和docData调用的意外行为。可观察链涉及使用docData使用额外的用户数据丰富从this.stream_service.readFeed()获取的活动。然而,我遇到了docData调用的意外行为,特别是tap
和switchMap
运算符。
我预计docData next和combineLatest next日志只出现一次,因为activity_response数组中只有一个项。
尽管有可观察到的发射值,但tap和switchMap操作符的日志记录次数比预期的要多。docData next和combineLatest next日志出现两次而不是一次。
代码如下:
private post_activity$ = toObservable(this.post).pipe(
// Use switchMap to switch to a new observable based on the latest value of post$
switchMap((post) => {
// Check if post is falsy (null, undefined, etc.)
if (!post) {
// If post is falsy, return an EMPTY observable (essentially a complete and empty observable)
return EMPTY;
}
// Call the current_user() function to get the current user
const current_user = this.current_user();
// Determine the feed_type based on whether the current user matches the post's user_id
const feed_type =
current_user && current_user?.uid === post.user_id ? 'user' : 'public';
// Return the result of calling this.stream_service.readFeed()
return this.stream_service.readFeed(
feed_type,
post.user_id,
1,
post.stream_activity_id
);
}),
tap((post_activity) => {
console.log('%cPost Activity', 'color: pink', post_activity);
}),
switchMap((activity_response) => {
// Check if activity_response is falsy
if (!activity_response) {
// If it is, return an EMPTY observable
return EMPTY;
}
// Call a service method to enrich the activities in activity_response
if (activity_response.length > 0) {
const activity = activity_response[0]; // 1 activity
console.log('Activity', activity); // This will log once
return docData(doc(this.firestore, 'users', activity.actor), {
idField: 'id',
}).pipe(
tap({
next: (user) => console.log('docData next', user),
error: (error) => console.log('docData error', error),
complete: () => console.log('docData complete'),
}), // this will log twice
switchMap((user: any) => {
const activity_user = {
username: user.username,
pronouns: user.pronouns,
avatar_url: user.avatar_url,
photo_url: user.photo_url,
};
return of({
user: activity_user,
activity: activity,
liked:
!!activity.own_reactions?.like &&
activity.own_reactions.like[0].user_id ===
this.user_service.current_user()?.uid,
});
}),
tap({
next: (activities) => console.log('combineLatest next', activities),
error: (error) => console.log('combineLatest error', error),
complete: () => console.log('combineLatest complete'),
}) // this will log twice too
);
} else {
return EMPTY;
}
}),
tap(() => {
this.count.set(this.count() + 1);
console.log('%cCount', 'color: lime', this.count()); // Count 2
})
);
字符串
什么可能导致可观察链中的意外行为,以及如何确保docData next和combineLatest next日志按预期只出现一次?
任何关于调试和解决此问题的见解或指导将不胜感激。谢谢!
附加信息:
我添加了一些代码片段来检查隔离它是否会记录docData()两次。然而,我最终让事情变得更加令人困惑,因为我发现不仅docData()只记录一次(正如预期的那样),而且我在switchMap中的代码也只记录一次。这真是令人难以置信!
data$ = docData(
doc(this.firestore, 'users', activity.actor)
).pipe(
tap({
next: (user) => console.log('docData next', user),
error: (error) => console.log('docData error', error),
complete: () => console.log('docData complete'),
}) // this will log twice
);
private readonly data = toSignal(this.data$);
型
1条答案
按热度按时间0yg35tkg1#
从你所展示的来看,唯一的原因可能是docdata发出了多个值。这是tap可以记录两次的唯一方式。如果每次的用户都是相同的,那么docdata可能出于某种原因返回了两次。
尝试将管道更改为:
字符串
评价结果如下:
如果第一次点击打印2x,第二次点击打印1x,那么这意味着docData两次发出相同的用户名。
如果两个点击都打印了2x,那么docData会发出2个 * 不同的 * 用户(不同的用户名,但是查询的id相同)。
请注意,这两种情况都表明问题在docData中,但它们应该有助于缩小原因范围。
编辑:我不熟悉
toSignal
,但它很有可能是重复数据删除(有效地使用distinctUntilChanged
),这就是为什么你的代码版本打印了两次tap,但订阅信号的东西只被调用一次。