rxjs

To an experienced RxJS user, marble diagrams are helpful. To someone just starting out with RxJS, they look like a little kid’s drawing in art class.

对于经验丰富的RxJS用户,大理石图会有所帮助。 对于刚开始使用RxJS的人来说,它们看起来像是美术课上的小孩绘画。

I’m by no means an expert user of RxJS, but I’ve used it enough to make sense of these “marble diagrams”. I can finally use rx marbles with confidence, and I want you to get there too.

我绝不是RxJS的专家用户,但是我已经足够使用它来理解这些“大理石图”了。 我终于可以放心使用rx大理石了,我也希望您也能到达那里。

Note: this post assumes you are comfortable with the concept of asynchronous programming and Observables.

注意:本文假定您对异步编程和Observables的概念感到满意。

让我们开始简单 (Let’s start simple)

Observables are asynchronous operations, so we need a way to represent the passage of time. This can be done with an arrow moving left to right.

可观察值是异步操作,因此我们需要一种表示时间流逝的方法。 这可以通过左右移动箭头来完成。

The vertical line at the end of an arrow represents the successful completion of an Observable. But what if the Observable has an error?

箭头末端的垂直线表示Observable的成功完成。 但是,如果Observable有错误怎么办?

If an error occurs in an Observable, it is represented by an X. Once an error is emitted, the Observable does not emit any further values.

如果Observable中发生错误,则用X表示。一旦发出错误,Observable将不再发出任何其他值。

And finally, those colorful little circles represent values and can show up anywhere on the arrow’s timeline. These values can be strings, numbers, booleans, or any other basic type.

最后,这些彩色的小圆圈代表值,并且可以显示在箭头的时间轴上的任何位置。 这些值可以是字符串,数字,布尔值或任何其他基本类型。

拼凑在一起 (Putting the pieces together)

Remember, marble diagrams help us understand operators. And operators come in two forms:

请记住,大理石图可帮助我们了解操作员。 运算符有两种形式:

  1. Creation operators (of, from, timer, etc.)创建运算符(来自,来自计时器等)
  2. Pipeable operators (map, take, filter, etc.)管道运算符(地图,获取,过滤器等)

Creation operators are standalone (they create their own values), which means their marble diagrams are just a single arrow:

创建运算符是独立的(它们创建自己的值),这意味着它们的大理石图只是一个箭头:

rx marbles)rx大理石)

And pipeable operators need an “Input Observable” as their source because they do not emit values themselves. They simply “operate on” those values. Therefore, you’ll see pipeable operator marble diagrams with 1 or more “Input Observables”, the operator itself, and an “Output Observable”.

可管道运算符需要“ Input Observable”作为其源,因为它们本身不会发出值。 他们只是“操作”这些价值观。 因此,您将看到带有1个或多个“ Input Observables”,运算符本身和“ Output Observable”的可管道运算符大理石图。

Just think of these like normal functions (technically “pure functions”) except their arguments are observables and their return values are observables.

只需将它们视为普通函数(技术上为“纯函数”),只是它们的参数是可观察的,而其返回值是可观察的。

Here’s an example:

这是一个例子:

concat operator
concat运算符

It is important to note that the order of the input Observables matters in some cases. While some operators would return the same output Observable regardless of the order of the two input Observables, some operators actually use the order of those inputs to form the output. The above Observable concat()is a perfect example of this. Notice how the output Observable returns the three values emitted from input Observable #1 before returning the two values emitted from input Observable #2 even though both of Observable #2’s values were emitted prior to the final two values of Observable #1.

重要的是要注意,输入Observable的顺序在某些情况下很重要。 尽管某些运算符将返回相同的输出Observable而不管两个输入Observable的顺序如何,但某些运算符实际上使用这些输入的顺序来形成输出。 上面的Observable concat()是一个完美的例子。 请注意,即使两个Observable#2的值都在Observable#1的最后两个值之前发出,输出Observable还是在返回从输入Observable#2发出的两个值之前如何返回输入Observable#1发出的三个值

In RxJS, we generally refer to input Observable #1 as the “Outer Observable” and input Observable #2 as the “Inner Observable”.

在RxJS中,我们通常将输入Observable#1称为“外部可观测”,将输入Observable#2称为“内部可观测”。

As I said, the order doesn’t always matter. Take the merge() operator for example:

如我所说,顺序并不总是很重要。 以merge()运算符为例:

rx marbles)rx大理石)

No matter what order the two input Observables are called, the output Observable will always emit the same values (trust me for now — we’ll learn to read these in a few minutes).

无论调用两个输入Observable的顺序如何,输出Observable都将始终发出相同的值(现在请相信我-我们将在几分钟内学会读取它们)。

暂停:让我们确保在几件事上保持清晰 (Pause: Let’s make sure we’re clear on a few things)

To understand this post going forward, you need to get clear with some terminology:

为了理解本文的发展,您需要弄清楚一些术语:

Outer Observable: The outer Observable, or what I have called “input Observable #1”, or “OO”, is the Observable that is at the top of each diagram. It is called “outer” because it usually appears that way when writing code:

外部可观察到的:外部可观察到的,即我所谓的“输入可观察的#1”或“ OO”,是每个图顶部的可观察到的。 之所以称为“外部”,是因为在编写代码时通常以这种方式出现:

// An example that shouldn't make sense yet to yououterObservable().pipe( mergeMapTo(   innerObservable(),    (x, y) => x + y  ));

Inner Observable: The inner Observable, or what I have called “input Observable #2”, or “IO”, is the Observable below the outer Observable, but before the operator in each diagram. It is called “inner” for the same reason as above.

内部可观测值:内部可观测值,或我所谓的“输入可观测值2”或“ IO”,是外部可观测值下方但在每个图中的运算符之前的可观测值。 出于与上述相同的原因,它被称为“内部”。

Output Observable: When using RxJS operators, sometimes there are many layers between the input Observable(s) and the output Observables, but you can think of the output Observable as the “return value”.

输出可观测值:使用RxJS运算符时,有时输入可观测值和输出可观测值之间有很多层,但是您可以将输出可观测值视为“返回值”。

input Observable: This is a general term to identify any Observable that is NOT the “output Observable”. In other words, both the inner and outer Observables are considered “input” Observables.

输入可观察值:这是一个通用术语,用于标识不是“输出可观察值”的任何可观察值。 换句话说,内部和外部可观察对象都被视为“输入”可观察对象。

And lastly, not all operators follow the concept of “inner” and “outer” Observables. To some operators like combineLatest (we’ll see this later), all Observables are treated equally, and therefore, we refer to each Observable as an “input Observable”.

最后,并非所有运营商都遵循“内部”和“外部”可观测对象的概念。 对于诸如combineLatest运算符(我们将在后面看到),所有Observable均被平等对待,因此,我们将每个Observable称为“输入Observable”。

让我们开始翻译其中一些 (Let’s begin translating a few of these)

Below are some of the most common operators and how to translate their marble diagrams.

以下是一些最常见的运算符以及如何转换其大理石图。

We’ll start easy with the map() operator.

我们将从map()运算符开始。

rx marbles)rx大理石)

The top arrow represents our input Observable, and it emits three values. This one is pretty straightforward if you’ve worked with the map function on a basic JavaScript array. All you’re doing is transforming the values emitted from the input Observable by a factor of 10. Here is the marble diagram recreated in code:

上方的箭头代表我们的输入Observable,它发出三个值。 如果您已经在基本JavaScript数组上使用map函数,那么这非常简单。 您要做的只是将输入Observable发出的值转换10倍。这是在代码中重新创建的大理石图:

const { interval } = Rx;
const { map, take } = RxOperators;// The input observable will emit the values 1, 2, 3
// in 1 second intervals
function inputObservable() {const returnValues = [1, 2, 3];return interval(1000).pipe(take(returnValues.length),map(val => returnValues[val]));
}// =====================================
// Don't worry about anything above this
//
// Just know that the input Observable
// returns the values 1, 2, 3
// =====================================inputObservable().pipe(// 10 * 1 = 10// 10 * 2 = 20// 10 * 3 = 30map(x => 10 * x)
)
Visualization of the code above
可视化上面的代码

We’ll do one more simple one and then jump into some harder ones. Below is the take() operator.

我们将再做一个简单的例子,然后跳入更难的例子。 下面是take()运算符。

In the above diagram, the input Observable emits four integers — 1, 2, 3, and 4. If you were to subscribe to this input Observable directly, you would receive those exact four values. But if you pipe the take(2) operator, the new output Observable will grab the first two emitted values, and then it will complete. The input Observable will still emit the last two values, but our output Observable will not see them because it has completed after two values. Below is the code and visualization.

在上图中,输入Observable发出四个整数-1、2、3和4。如果您直接预订此输入Observable,则将接收到这四个值。 但是,如果通过管道传递take(2)运算符,则新的输出Observable将获取发出的前两个值,然后它将完成。 输入Observable仍将发出最后两个值,但是我们的输出Observable将看不到它们,因为它在两个值之后已完成。 下面是代码和可视化。

const { interval } = Rx;
const { map, take } = RxOperators;// The input observable will emit the values 1, 2, 3
// in 1 second intervals
function inputObservable() {const returnValues = [1, 2, 3];return interval(1000).pipe(take(returnValues.length),map(val => returnValues[val]));
}// =====================================
// Don't worry about anything above this
//
// Just know that the input Observable
// returns the values 1, 2, 3
// =====================================inputObservable().pipe(take(2)
)
the output Observable
输出可观察

switchMap运算符(switchMap Operator)

Let’s look at some more difficult operators now. We’ll start with switchMap() as this is a common, yet sometimes difficult to understand operator.

现在让我们来看一些更困难的运算符。 我们将从switchMap()开始,因为这是一个常见的运算符,但有时很难理解。

And this is where these diagrams start getting a bit confusing, but by walking through each emitted value, we can start to make sense of it.

这就是这些图开始变得有些混乱的地方,但是通过遍历每个发出的值,我们可以开始理解它。

But before we go into that, let me highlight a few things.

但是在开始之前,我先强调一些事情。

  • Notice that in this marble diagram, there are two input Observables, which means the code that you will see below this explanation is a bit more confusing. With an operator like switchMap(), Input Observable #1 is called the “Outer Observable” and Input Observable #2 is called the “Inner Observable”

    请注意,在此大理石图中,有两个输入Observables,这意味着您将在此解释下方看到的代码更加混乱。 使用类似switchMap()的运算符,输入可观察值1称为“外部可观察”,输入可观察值2称为“内部可观察”

  • This example is from the official RxJS documentation because the rx marbles example is outdated (as of the time of writing) and uses the deprecated resultSelector.

    本示例来自RxJS官方文档,因为rx marbles示例已过期(截至撰写本文时),并且使用了不赞成使用的resultSelector 。

  • Because this is an example from the official documentation, you will notice that in the operator, there are a few dashes “-” within the function. You’ll also notice the “|” at the end. These simply represent the passage of time just as we have seen in the actual arrows. The more dashes, the more time between the emitted values. As you can see, the first two values of the outer observable take longer to emit than the last and have more dashes.因为这是官方文档中的示例,所以您会注意到,在运算符中,函数中有一些破折号“-”。 您还会注意到“ |” 在最后。 正如我们在实际箭头中所看到的,它们只是代表时间的流逝。 破折号越多,发射值之间的时间越长。 如您所见,外部observable的前两个值发射的时间比最后一个长,并且具有更多的破折号。

Here’s the diagram again so you don’t have to keep scrolling up.

再次显示该图,因此您不必继续向上滚动。

Let’s assume that each orange vertical line at the top represents 1 second. This means that the outer Observable (OO) emits values at 1, 4, and 5.5 seconds while the inner Observable (IO) emits values every second for 3 seconds, starting immediately after subscription (time zero).

假设顶部的每条橙色垂直线代表1秒。 这意味着外部Observable(OO)在1、4和5.5秒时发出值,而内部Observable(IO)在订阅后立即开始(时间为零),每3秒每秒发出一次值。

The first three output values (10, 10, 10) seem pretty easy. Just multiply 1 x 10 = 10 for each of them according to the operator logic. Based on these first three values, we could say that for each OO value, the IO emits all of its values.

前三个输出值(10、10、10)似乎很简单。 只需根据操作员逻辑将每个乘以1 x 10 = 10。 基于这前三个值,我们可以说对于每个OO值,IO都会发出其所有值。

This assumption seems to hold true for the first output value of 30… And the second output value of 30…

对于第一个输出值30…和第二个输出值30…,此假设似乎成立。

But shouldn’t it emit a final value of 30??

但是它不应该发出30的最终值吗?

This is where the switchMap logic comes in. Every time the OO emits a value, the IO emits all of its values unless the OO emits a new value before the IO finishes emitting all of its values. We can see this when the OO emits a value of 5 and it appears that our last value of 30 is “canceled”.

这就是switchMap逻辑的所在。每次OO发出一个值时,IO都会发出其所有值,除非OO在IO完成发出其所有值之前先发出一个新值。 当OO发出的值为5且我们的最后一个值为30时,我们可以看到这一点。

Takeway: What the marble diagram above is attempting to convey is that the output Observable of a switchMap operator is dictated by the outer Observable’s emitted values. How would you know this by looking at the diagram? In this case, you probably wouldn’t. Sometimes marble diagrams are only meaningful in conjunction with the operator description within the documentation. Here’s what the official documentation states:

总结:上面的大理石图试图传达的是, switchMap运算符的输出Observable由外部Observable的发射值决定。 通过查看图表,您如何知道这一点? 在这种情况下,您可能不会。 有时,大理石图仅与文档中的操作员说明结合使用才有意义。 官方文件说明以下内容:

Projects each source value to an Observable which is merged in the output Observable, emitting values only from the most recently projected Observable.

将每个源值投影到一个Observable,将其合并到输出Observable中,仅从最近投影的Observable发出值。

Translated, the “source value” would be the outer Observable values, while the “most recently projected Observable” represents the inner Observable values.

换算后,“源值”将是外部可观察值,而“最近投影的可观察”则是内部可观察值。

To some, this may not be confusing. But to me, it is. That’s why I generally start with the marble diagram, use some deductive reasoning, and then confirm my understanding with the official documentation (or other online tutorials).

对于某些人来说,这可能不会造成混淆。 但是对我来说是。 这就是为什么我通常从大理石图开始,使用一些演绎推理,然后通过官方文档(或其他在线教程)确认我的理解。

Another takeaway: There is no “formula” for interpreting marble diagrams. As you’ll see in subsequent examples, interpreting marble diagrams is kind of like solving a logic puzzle. By figuring out what the operator does not do, you will be able to figure out what it does (for you Taleb readers — “via negativa”).

另一个要点:没有用于解释大理石图的“公式”。 正如您将在后续示例中看到的那样,解释大理石图有点像解决逻辑难题。 通过弄清楚操作员不做什么,您将能够弄清楚它的工作(对于您的Taleb读者-“通过negativa”)。

Below is some code that attempts to replicate the diagram above (note that there are more efficient ways to write the inner and outer observables, but this was the clearest way I could think of).

下面的代码尝试复制上面的图(请注意,有更有效的方式编写内部和外部可观察对象,但这是我能想到的最清晰的方法)。

const { interval, Observable } = Rx;
const { map, take, switchMap, startWith } = RxOperators;// Emit value 1 at 1 second
// Emit value 3 at 4 seconds
// Emit value 5 at 5.5 seconds
// Complete at 5.5 seconds
function outerObservable() {return new Observable(subscriber => {setTimeout(() => {subscriber.next(1);}, 1000);setTimeout(() => {subscriber.next(3);}, 4000);setTimeout(() => {subscriber.next(5);subscriber.complete();}, 5500);})
}// Emit the value 10 every second, starting at time 0, for 3 total seconds
function innerObservable() {const valuesToEmit = [10, 10];return interval(1000).pipe(take(valuesToEmit.length),map(index => valuesToEmit[index]),startWith(10) // emits 10 at time zero)
}outerObservable().pipe(switchMap(outerObservableValue => {return innerObservable().pipe(map(innerObservableValue => {return innerObservableValue * outerObservableValue;}));})
);
Visualization of the code above
可视化上面的代码

另一个示例:CombineLatest(Another example: combineLatest)

Now that we have a basic idea of how to interpret a marble diagram, let’s practice another one — combineLatest.

现在,我们对如何解释大理石图有了基本的了解,让我们练习另一个方法-CombineLatest。

Note: combineLatest doesn’t follow the concept of “outer Observable” and “inner Observable”. With this operator, all Observables are treated equally.

注意: combineLatest不遵循“外部可观察”和“内部可观察”的概念。 使用此运算符,所有可观察对象均被平等对待。

This is a good one because you can infer how it works without any descriptions. Starting with the first emitted value, you’ll notice that there is no output value.

这是一个很好的选择,因为您无需任何说明即可推断其工作方式。 从第一个发出的值开始,您会注意到没有输出值。

This tells us that combineLatest requires both input Observables to emit at least one value before it emits the first output value.

这告诉我们, combineLatest要求两个输入Observable都必须发出至少一个值才能发出第一个输出值。

The next emission comes from the second input Observable, and you’ll see that when it emits, we get our first output value, “1A”.

下一个发射来自第二个输入Observable,您将看到当它发射时,我们得到第一个输出值“ 1A”。

Clearly, this operator is combining the values from each input Observable (hence the name). But at this point, we don’t exactly know how yet.

显然,此运算符正在组合来自每个输入Observable的值(因此具有名称)。 但是目前,我们还不完全知道。

Next up, the first input Observable emits the value 2, and we see that our output value is “2A”. It is obvious where the 2 came from, but where did the “A” come from? Well, consistent with its name, “A” was the latest value of the second input Observable.

接下来,第一个输入Observable发出值2,我们看到我们的输出值为“ 2A”。 很明显2是从哪里来的,但是“ A”是从哪里来的呢? 好吧,与其名称一致,“ A”是第二个输入Observable的最新值。

Jumping to the last output value, “5D”, you can see that input Observable #1 emitted the value 5, and the latest emitted value from input Observable #2 was “D”.

跳到最后一个输出值“ 5D”,您可以看到输入Observable#1发出了值5,而来自输入Observable#2的最新发出的值是“ D”。

让我们使用“过滤器”运算符保持滚动 (Let’s keep it rolling with the “filter” operator)

We’re back to having only one input Observable. Starting with the first emitted value of 2, we see that there is no output value. Looking at the filter operator logic, we can see that we are looking for emitted values that are greater than 10. We can logically conclude that since the first emitted value was less than 10, it was ignored and there was no output emission.

我们回到只有一个可观察输入。 从第一个发射值2开始,我们看到没有输出值。 查看过滤器运算符的逻辑,可以看到我们正在寻找大于10的发射值。我们可以从逻辑上得出结论,由于第一个发射值小于10,因此将其忽略并且没有输出发射。

By the second value, our understanding is confirmed. The second emitted value is 30, which is greater than 10, and we see that because of this, the output Observable emits the value.

通过第二个值,我们的理解得到了证实。 第二个发出的值是30,大于10,因此我们看到输出Observable发出了该值。

另一个:拉链 (Another one: zip)

Looks a lot like combineLatest right?

看起来很像combineLatest对吗?

The first two output Observable values of “1A” and “2B” seem to suggest that zip works exactly like combineLatest. But once we get to the third output Observable value of “3C”, things don’t make sense anymore…

前两个输出的Observable值“ 1A”和“ 2B”似乎表明zip工作方式完全类似于combineLatest 。 但是,一旦达到“ 3C”的第三个输出可观察值,事情就不再有意义了……

If I were reading this marble diagram having never used zip before, I would test out a few assumptions until my assumption held true for all the output values. My initial assumption might have been that this operator combines the latest values of the input Observables. This is proven false by the output value of “3C” because if it emitted the latest values, this should have been “3D”.

如果我正在阅读从未使用过zip大理石图,则我将测试一些假设,直到我的假设对所有输出值都成立为止。 我最初的假设可能是该运算符结合了输入Observable的最新值。 输出值“ 3C”证明这是错误的,因为如果发出最新值,则该值应该为“ 3D”。

So my new assumption — the zip operator “matches up” values of each input Observable. For example, the fourth value of input Observable #1 should be combined with the fourth value of input Observable #2.

因此,我的新假设zip运算符“匹配”每个输入Observable的值。 例如,输入可观察#1的第四值应与输入可观察#2的第四值进行组合。

The fourth value of each Observable is 4 and “D”. Do we have an output value of “4D”?

每个Observable的第四个值是4和“ D”。 我们的输出值为“ 4D”吗?

Yes we do!

是的,我们愿意!

And the fifth value of each Observable is 5 for input Observable #1 and nothing for input Observable #2.

输入Observable#1的每个Observable的第五个值是5,而输入Observable#2的第五个值则是零。

Since both input Observables don’t have a fifth value, there is nothing to “match up” and therefore no output value.

由于两个输入Observable都没有第五个值,因此没有什么可“匹配”的,因此也没有输出值。

上一个:mergeMapTo(具有挑战性) (Last One: mergeMapTo (challenging))

Note: I chose this operator because it looked difficult. I have never actually used this operator in my code and don’t know of a good reason to (comment if you do!)

注意:我选择此运算符是因为它看起来很困难。 我从未在代码中实际使用过该运算符,也不知道有充分的理由(如果您这样做,请评论!)

By scanning the operator logic, we can tell that the two input Observables are being combined into a single string value. So let’s use this to make our initial assumption as to how this operator works.

通过扫描运算符逻辑,我们可以知道两个输入Observables正在组合为单个字符串值。 因此,让我们用它来对该操作符的工作方式进行初步假设。

I see that the first output value combines both Observables. This doesn’t tell me much because there are several other operators that do the same (combineLatest, zip, etc.).

我看到第一个输出值结合了两个Observables。 这不会告诉我太多,因为还有其他几个运算符也可以执行相同的操作(combineLatest,zip等)。

The next output is “C1”. This also doesn’t tell me much because combineLatest does the same thing…

下一个输出是“ C1”。 这也没有告诉我太多,因为combineLatest做同样的事情……

The next output value is “A2”, and this is where we start building our assumption. If this operator were combineLatest, this output value should have been “C2” (the latest two values). If this operator were zip, the value should have been “B3”. So now, we must figure out what logic is happening to produce a value of “A2”.

下一个输出值是“ A2”,这是我们开始建立假设的地方。 如果此运算符为combineLatest ,则此输出值应为“ C2”(最近的两个值)。 如果此运算符为zip ,则值应为“ B3”。 因此,现在,我们必须弄清楚产生“ A2”值的逻辑是什么。

This operator is called mergeMapTo (emphasis on “merge”), so it is probably additive. I also see a lot of output values. So a good assumption is that this operator is coming up with every possible combination of input Observable values. Let’s see if this holds true…

此运算符称为merge MapTo(强调“合并”),因此它可能是加法运算。 我也看到很多输出值。 因此,一个很好的假设是该运算符将得出输入可观察值的所有可能组合。 让我们看看这是否成立……

First, let’s list off all the possible combinations of values from the two input Observables:

首先,让我们列出两个输入Observable的所有可能值组合:

A1, A2, A3, C1, C2, C3, B1, B2, B3

And do all of these values appear as output values? Yep.

并且所有这些值都显示为输出值吗? 是的

So the last part of this equation is to figure out how this is being applied. Because with operators, the order and timing of things matters.

因此,该方程式的最后一部分是弄清楚如何应用它。 因为对于运营商而言,事物的顺序和时机至关重要。

Above, I’ve listed all of the possible values using the two input Observable emissions. But the order which I listed them in is NOT the order which they were emitted in. Here is the order they were emitted:

上面,我使用两个输入的“可观察到的排放量”列出了所有可能的值。 但是我列出它们的顺序不是发出它们的顺序。这是发出它们的顺序:

A1, C1, A2, C2, A3, C3, B1, B2, B3

So the question is… Why did “C1” come before “A2”? And why did “A3” come after “C2”? There is clearly something going on with the order of emissions here.

所以问题是……为什么“ C1”比“ A2”要早? 为什么“ A3”在“ C2”之后? 显然,这里的排放顺序正在发生某些事情。

Here’s the diagram again so you don’t have to keep scrolling up.

再次显示该图,因此您不必继续向上滚动。

I’m noticing a couple of things here:

我在这里注意到了几件事:

  • Each time either of the input Observables emit a value, the output Observable may, but doesn’t always emit a value (unlike combineLatest)

    每次输入Observable的每一个发出一个值时,输出Observable可能会但不一定总是发出一个值(与combineLatest不同)

  • The output Observable never emits a value that hasn’t been emitted by the input Observables yet输出Observable永远不会发出输入Observables尚未发出的值
  • The inner Observable (IO) is directly related to the output value. In other words, each time it emits a new value (1, 2, 3), the output Observable emits a value with that newly emitted value in it. For example, take a look at the output value “A3”. The outer Observable (OO) just emitted the value “B”, and the IO just emitted the value 3. But in this case, the output value doesn’t have “B” in it at all, which means that the output isn’t concerned with the timing of OO, but it is concerned with the timing of IO.

    内部的Observable(IO)与输出值直接相关。 换句话说,每当它发出一个新值(1、2、3)时,输出Observable就会发出一个其中包含该新发出的值的值。 例如,看一下输出值“ A3”。 外部Observable(OO)刚刚发出值“ B”,而IO刚刚发出值3。但是在这种情况下,输出值中根本没有“ B”,这意味着输出为“ B”。 Ť涉及OO的定时,但它涉及IO的定时。

  • The output values look random at first, but notice how “A1”, “A2”, and “A3” are spaced out evenly — the exact same spacing as the IO. This also occurs for “B1”, “B2”, and “B3”, and “C1”, “C2”, “C3”— they are spaced out evenly.首先,输出值看起来是随机的,但请注意“ A1”,“ A2”和“ A3”是如何均匀隔开的-与IO完全相同的间距。 对于“ B1”,“ B2”和“ B3”以及“ C1”,“ C2”,“ C3”,也会发生这种情况-它们被均匀地隔开。

So with these observations, here is my conclusion as to how this operator logic works:

因此,根据这些观察,我得出了关于此运算符逻辑如何工作的结论:

Each time the outer Observable (input Observable #1) emits a value, a new “sequence” (not a new Observable) is fired. This sequence is entirely based on the number of values and timing of values seen in the inner Observable (input Observable #2).

每次外部Observable(输入Observable#1)发出一个值时,都会触发一个新的“序列”(而不是一个新的Observable)。 此序列完全基于内部Observable(输入Observable#2)中看到的值的数量和值的时序。

Here’s some code to represent the diagram for those interested:

这是一些代码,用于为感兴趣的人表示该图:

const { interval, Observable } = Rx;
const { map, take, switchMap, startWith, mergeMapTo } = RxOperators;function outerObservable() {return new Observable(subscriber => {setTimeout(() => {subscriber.next("A");}, 1000);setTimeout(() => {subscriber.next("C");}, 1500);setTimeout(() => {subscriber.next("B");subscriber.complete();}, 4000);})
}// Emit the value 10 every second
function innerObservable() {return interval(1000).pipe(map(val => val + 1),take(3));
}outerObservable().pipe(mergeMapTo(innerObservable(),(x, y) => x + y)
);
Visualization of code above
上面代码的可视化

有多种方法可以做到这一点(There is more than one way to do it)

Reading marble diagrams is more of an art than a science. Once you understand the components of a marble diagram, you can use deductive logic (as seen above), you could search the internet for tutorials on the specific operator you are using (probably quicker than deductive logic), or you could painfully learn to read the RxJS documentation and all of the jargon associated with that. Or… You could combine all of these approaches into one (my preference).

阅读大理石图更多的是一门艺术,而不是一门科学。 一旦理解了大理石图的组成部分,就可以使用演绎逻辑(如上所示),可以在互联网上搜索正在使用的特定运算符的教程(可能比演绎逻辑更快),或者可以痛苦地学习阅读RxJS文档以及与此相关的所有行话。 或者……您可以将所有这些方法组合为一种(我的偏爱)。

And as you can see, the more operators that you learn, the easier it is to learn new ones because you can start making associations between them and recognizing operators that are similar to one another.

正如您所看到的,您学习的运算符越多,学习新的运算符就越容易,因为您可以开始在它们之间建立关联并识别彼此相似的运算符。

运营商决策树 (The Operator Decision Tree)

And finally… Just because you can read marble diagrams does not mean that you need to learn every operator. While learning all the operators thoroughly would be extremely helpful, not all of us have the time to do so (and after using RxJS long enough, you’ll find yourself re-using the same few operators over and over again). And for that reason, here’s a workflow that I’ve used with RxJS:

最后……仅仅因为您可以阅读大理石图并不意味着您需要学习每个操作员。 尽管全面了解所有运算符将非常有帮助,但并非所有人都有时间这样做(并且在使用RxJS足够长时间之后,您会发现自己一次又一次地重复使用相同的少数运算符)。 因此,这是我与RxJS一起使用的工作流程:

  1. Identify the problem you’re trying to address (aka you know you need an operator but aren’t sure which one)确定您要解决的问题(也就是知道您需要操作员,但不确定是哪一个)
  2. Use the operator decision tree

    使用操作员决策树

  3. Interpret the marble diagram of the operator that the decision tree chooses解释决策树选择的操作员的大理石图
  4. If your interpretation of the operator seems like it addresses the problem from step #1, you’re done. If not, repeat these steps until you’ve narrowed it down enough.如果您对运算符的解释似乎解决了步骤1中的问题,则说明您已完成。 如果没有,请重复这些步骤,直到将其缩小到足够的范围为止。

而已! (That’s it!)

Here are some other articles of mine you might like:

这是您可能会喜欢的其他一些文章:

Three things I wish I knew when I started using Angular 2+

当我开始使用Angular 2+时我希望知道的三件事

The most confusing thing in JavaScript: The this keyword

JavaScript中最令人困惑的事情: this关键字

翻译自: https://medium.com/@zach.gollwitzer/how-to-read-an-rxjs-marble-diagram-f6e8dfa29781

rxjs


http://www.taodudu.cc/news/show-3083059.html

相关文章:

  • 大理石在哪儿
  • 大理石在哪【搜索排序】
  • [周末训练]大理石
  • 黑金花大理石_黑色是百搭更是经典 — 黑金花大理石简介及案例欣赏
  • c++ 大理石
  • 2022-2027年中国大理石板材市场竞争态势及行业投资潜力预测报告
  • 大理石
  • 【最新】智慧图书馆管理软件应该全面考量各个模块的建设
  • 开源图书管理_图书馆资源探索开源选项
  • django基于python的图书馆管理系统--python-计算机毕业设计
  • 我有一个自己的数字图书馆
  • python爬虫——爬取图书馆借阅数据
  • 灵魂的吞噬 评论google图书馆
  • 图情论文笔记 | 学术图书馆“十四五”规划的思考(杨新涯)
  • 图书馆抢座设置
  • Google图书馆现在开幕
  • 90图书馆使用说明
  • 谷歌数字图书馆
  • Google数字图书馆
  • 全球IP地址短缺的危机 思科可同时支持IPv4和IPv6
  • 转载:记忆学习策略
  • 谈话的力量
  • 参加《互联网技术创新和产业发展论坛》有感
  • 网友创作山寨版英文歌曲《上海滩》
  • 民众不要相信世界末日传言
  • ContentPrivider
  • T13735 fateice-string洛谷八连测2
  • 八连测之一fateice-string
  • 《百面机器学习》试读 | AI热门应用之游戏中的人工智能
  • 人工智能在游戏领域的应用

rxjs_如何阅读rxjs大理石图相关推荐

  1. 多看阅读怎么更换背景图

    看阅读怎么更换背景图,相信也是有许多的小伙伴在使用这款小说软件阅读小说,自己对此也是非常的关心这个怎么更换背景图,毕竟一直都是这个背景图颜色看腻了,下面就给加大家带来详细介绍. 多看阅读怎么更换背景图 ...

  2. GFS论文阅读思维导图

    GFS论文阅读思维导图 该文章记录了阅读GFS论文的笔记,并将其以思维导图的形式展现,便于阅读与理解.

  3. 深度学习论文阅读进阶路径图

    ↑ 点击上方[计算机视觉联盟]关注我们 介绍: 列表选自github用户floodsung发起的Deep Learning Papers Reading Roadmap项目,主要目标是收集深度学习论文 ...

  4. Java源码阅读(类图自动生成工具)

    菜鸟上路,在有了基础以后,总需要去阅读大量的优秀的源码,但在面对一个项目工程大量的代码不知道怎么下手.只是跟着敲代码,我觉得这个方法不太妥当. 我是个方法论者,在收集查阅了大量的资料后发现画代码结构图 ...

  5. 如何用思维导图提高阅读效率?分享高效阅读思维导图模板及绘制技巧

    书是用文字表达其内容,千变一律的小方块字体,却散发着独特的魅力,阅读时或许用你的一目十行扫过去,可以大致了解到写了什么,但若深究起来你可能并不记得细节内容.就好像远远的看一面墙,你能看到墙面漂亮的颜色 ...

  6. 思维导图提高阅读效率简单的方法是什么?分享高效阅读思维导图模板及绘制技巧

    书是用文字表达其内容,千变一律的小方块字体,却散发着独特的魅力,阅读时或许用你的一目十行扫过去,可以大致了解到写了什么,但若深究起来你可能并不记得细节内容.就好像远远的看一面墙,你能看到墙面漂亮的颜色 ...

  7. MapReduce论文阅读思维导图

    [前言]准备开始经典课程MIT-6.824的学习之旅了,希望可以成功完成- 阅读mapreduce论文所做的思维导图,方便过后回顾.

  8. datetimepicker 更新值无效_文献阅读之Voronoi图的生成与更新

    通俗的说,在机器人导航方面,Voronoi图是一种将地图分区的方法,分区的界限即Voronoi图的边,常用作机器人远离障碍物避障的规划路径.本文主要参考了 Boris Lau 的论文和代码,对Voro ...

  9. 做孩子阅读的同行者[图]

    儿子从幼儿园开始就很喜欢看书,可能是受我俩爱看书的影响,在潜移默化中为他的阅读打下了良好的基础.特别是上一年级之前,他虽然连自己的名字也只能歪歪扭扭地画上几笔,可识字量却已将近五百个. 从最早的< ...

最新文章

  1. 【 C 】简化双链表插入函数(对在双链表中插入一个新值的简明程序的简化)
  2. 不要光仅仅知道ipconfig了,你out了
  3. php 单例模式原理,PHP单例模式demo详解
  4. windows下共享文件夹在Linux下打开
  5. 程序员该不该主动提加薪?| 畅言
  6. dotenv 是什么 怎么使用
  7. 小飞鱼二开 使用jwt TOKEN方式单点登录开发(代码)
  8. Bigemap GIS Office软件 报价单
  9. 美国苹果股价走势图(抢先看美股三大指数新动态)
  10. 碰见参数错误咋解决?
  11. 原生javascript手风琴图片切换案例
  12. 通达OAV12报表中心
  13. 盘点:怀一胎和怀二胎的4点不同
  14. 推荐4款最好用的远程桌面访问软件,亲测好评
  15. 痞子衡嵌入式:内存读写正确性压力测试程序(memtester)
  16. Soul应用提取聊天记录【2021年中】
  17. 计算机主机光驱弹不出来,光驱弹不出来,详细教您解决光驱弹不出来的方法
  18. 基于朴素贝叶斯的文本分类算法
  19. 【环境配置】cudnn无注册下载+无法下载问题
  20. pyecharts交互式动态可视化案例_全国各省近20年GDP 动态展示

热门文章

  1. ui设计移动端字体适配_移动端UI设计尺寸规范(示例代码)
  2. X-Files 目录及剧情简介
  3. [转]机器学习中距离和相似性度量分类体系
  4. 2012年重要的软件开发发展
  5. 图像处理--角点检测
  6. JSP志愿者在线报名系统
  7. 一看就懂的MySQL教程
  8. 《网络空间测绘技术与实践》正式发售,让网络空间作战“有图可依”
  9. [Telegram X]旧版分享 突破被锁群组
  10. 简单c语言练习题(第三期)