为什么有时将观察者分配给订阅的主体会导致错误?

huangapple go评论52阅读模式
英文:

Why does assigning an observer to a subject in the subscribe break sometimes?

问题

以下是翻译的部分:

"Imagine the following simple case:" -> "想象以下简单情况:"
"- you get some data from a source, resulting in an observable, lets call it obs$" -> "- 你从某个数据源获取了一些数据,得到一个可观察对象,我们称之为obs$"
"- you need to transform it (frex a simple synchronous sort) and hand the result some kind of subject, lets call it subject$$" -> "- 你需要对它进行转换(例如,简单的同步排序),然后将结果传递给某种主题,我们称之为subject$$"
"You now have several ways to implement it." -> "现在你有几种实现方法。"
"The simplest might look like:" -> "最简单的方法可能如下:"
"Works like a charm." -> "效果很好。"
"A bit later you write some more similar functions, and thus would like to separate the transformation from the assignment." -> "稍后,你编写了一些类似的函数,并希望将转换与赋值分开。"
"Basically you move the doSomething from the subscribe to a map in the pipe. This could look like:" -> "基本上,你将doSomething从subscribe移到管道中的map。这可能看起来像这样:"
"Works fine as well." -> "也能正常工作。"
"Though the assignment now looks a bit clunky, surely there is a better way to do this?" -> "尽管赋值现在看起来有点笨重,但肯定有更好的方法吧?"
"You might be tempted to go for something like:" -> "你可能会倾向于采用类似以下的方式:"
"But quickly find that this fails, as you've got no access to your outer scopes this." -> "但很快发现这会失败,因为你无法访问外部作用域的this。"
"The suggested solution looks like this:" -> "建议的解决方案如下:"
"Which works just fine in many cases." -> "在许多情况下都能正常工作。"
"Imagine my surprise, when all of a sudden I stumbled into a waterfall of errors:" -> "想象一下,当我突然遇到一连串的错误时,我感到非常惊讶:"
"EmptyError: no elements in sequence" -> "EmptyError:序列中没有元素"
"showing up in four completely unrelated places, bubbling up through the code, without an obvious place to even try catch it." -> "出现在四个完全不相关的地方,冒泡到代码中,甚至没有明显的地方可以捕捉它。"
"Now following the white rabbit, I searched for far too long until I finally managed to discover the place of origin." -> "现在,跟随白兔,我搜索了很长时间,直到最终找到了起源地。"
"Still it doesn't make any sense to me." -> "但我仍然不明白这对我来说没有意义。"
"Why is the observer "disconnecting" for a moment when there is no activity that could result in a complete?" -> "为什么观察者在没有可能导致完成的活动时会“断开连接”?"
"Funnily enough, the subject is catching back up shortly afterwards, so this is not completely breaking the assignment." -> "有趣的是,主题随后很快恢复,所以这并没有完全破坏赋值。"
"Of course, I can always use the slightly more verbose assignment, but understanding why this fails only in some cases would really help avoid those." -> "当然,我总是可以使用稍微冗长的赋值,但了解为什么这只在某些情况下失败会帮助避免这些问题。"

英文:

Imagine the following simple case:

  • you get some data from a source, resulting in an observable, lets call it obs$
  • you need to transform it (frex a simple synchronous sort) and hand the result some kind of subject, lets call it subject$$

You now have several ways to implement it. The simplest might look like:

obs$
	.pipe(
		takeUntil(this.#destroy$$)
	)
	.subscribe(
		result => { 
			this.subject$$.next(result.dSomething()) 
	}); 

Works like a charm. A bit later you write some more similar functions, and thus would like to separate the transformation from the assignment. Basically you move the doSomething from the subscribe to a map in the pipe. This could look like:

obs$
	.pipe(
		takeUntil(this.#destroy$$),
		map(result => result.dSomething())
	)
	.subscribe(res => { this.subject$$.next(res) }); 

Works fine as well. Though the assignment now looks a bit clunky, surely there is a better way to do this? You might be tempted to go for something like:

obs$
	.pipe(
		takeUntil(this.#destroy$$),
		map(result => result.dSomething())
	)
	.subscribe(this.subject$$.next);

But quickly find that this fails, as you've got no access to your outer scopes this. The suggested solution looks like this:

obs$
	.pipe(
		takeUntil(this.#destroy$$),
		map(result => result.dSomething())
	)
	.subscribe(this.subject$$);

Which works just fine in many cases.

Imagine my surprise, when all of a sudden I stumbled into a waterfall of errors:

EmptyError: no elements in sequence

showing up in four completely unrelated places, bubbling up through the code, without an obvious place to even try catch it.

Now following the white rabbit, I searched for far to long until I finally managed to discover the place of origin. Still it doesn't make any sense to me.

Why is the observer "disconnecting" for a moment when there is no activity that could result in a complete? Funnily enough, the subject is catching back up shortly afterwards, so this is not completely breaking the assignment.

Of course, I can always use the slightly more verbose assignment, but understanding why this fails only in some cases would really help avoid those.

答案1

得分: 2

这很难建议任何事情,因为我不知道你的代码的哪一部分以及哪个 RxJS 链导致了 EmptyError

但是,我怀疑问题可能来自 .subscribe(this.subject$$),因为这与 .subscribe(res => this.subject$$.next(res)); 不同。

所有 Subjects 表现得像 Observables 和 Observers 同时存在。Observers 实现了此接口,处理了所有三种通知类型。如果你使用 .subscribe(this.subject$$),那么你同时将来自源 Observable 的 errorcomplete 通知传递给 subject$$,这很可能是你的问题所在。当 obs$ 完成时,complete 通知也会传递给 subject$$,它也会完成,由于它是一个 Subject,它将不再发出任何 next,对于所有新的观察者,它只会传递 complete 通知,仅此而已。因此,这可能解释了为什么在使用 subject$$ 的链中的其他地方出现 EmptyError

使用 .subscribe(res => this.subject$$.next(res)); 只会传递 next 通知,而 completeerror 通知将被忽略。

英文:

Its very hard to suggest anything because I don't know what part of your code and what RxJS chain gives you the EmptyError.

However, I'm suspicious that the problem comes from .subscribe(this.subject$$) because this is not the same as .subscribe(res => this.subject$$.next(res));

All Subjects behave like Observables and observers at the same time. Observers implement this interface that handles all three notification types. If you use .subscribe(this.subject$$) you're passing also error and complete notifications from the source Observable to subject$$ and this is very like your problem. When obs$ completes, the complete notification is passed to subject$$ that completes as well and since it's a Subject it will never ever emit any next again and to all its new observers it'll just pass complete notification and that's it. So this might explain why you're seeing EmptyError somewhere else in you chains that use subject$$.

With .subscribe(res => this.subject$$.next(res)); you're only passing next notifications and complete or error notifications are ignored.

huangapple
  • 本文由 发表于 2023年2月16日 16:17:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/75469470.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定