forkjoin rxjs_RxJS傻瓜运算符:forkJoin,zip,combinateLatest和withLatestFrom

本文详细解释了RxJS中的forkJoin、zip、combineLatest和withLatestFrom这四个组合运算符的用法和区别。作者通过T恤印刷的例子展示了这些运算符如何在不同情况下合并多个可观察对象的数据,帮助开发者选择合适的运算符。

forkjoin rxjs

If you are confused about the differences between forkJoin, zip, combineLatest and withLatestFrom, you are not alone! :)

如果您对forkJoinzipcombineLatestwithLatestFrom之间的差异感到困惑,那么您并不孤单! :)

These 4 operators are what we know as combination operators - we use them when we need to join information from multiple observables.

这4个运算子是combination operators -当我们需要连接来自多个观测器的信息时,我们使用它们。

我应该使用哪个运营商? (Which operator should I use?)

That is what this article is for! We will talk about the usage and differences between these 4 operators in an easy to understand way, so you know which one to choose when the time comes.

这就是本文的目的! 我们将以一种易于理解的方式来讨论这4个运算符之间的用法和差异,以便您了解何时可以选择哪个。

建立 ( Setup )

Imagine you are printing t-shirts. Ms. Color holds the color information and Mr. Logo holds the logo information. Both of them will pick color and logo spontaneously. You will need to wait and combine these two information continuously in order to print t-shirts. Ms. Color and Mr. Logo represent two observables in our code - color$ and logo$.

想象一下您正在印刷T恤 。 Color女士保存color信息,Logo先生保存logo信息。 他们俩都会自发选择colorlogo 。 您将需要等待并连续地合并这两个信息才能打印T恤。 Color女士和Logo先生代表我们代码中的两个可观察对象-color color$logo$

you, ms. color & mr. logo

// 0. Import Rxjs operators
import { forkJoin, zip, combineLatest, Subject } from 'rxjs';
import { withLatestFrom, take, first } from 'rxjs/operators';

// 1. Define shirt color and logo options
type Color = 'white' | 'green' | 'red' | 'blue';
type Logo = 'fish' | 'dog' | 'bird' | 'cow';

// 2. Create the two persons - color and logo observables, 
// They will communicate with us later (when we subscribe)
const color$ = new Subject<Color>();
const logo$ = new Subject<Logo>();

// 3. We are ready to start printing shirt. Need to subscribe to color and logo observables to produce shirts, we will write code here later
...

// 4. The two persons(observables) are doing their job, picking color and logo
color$.next('white');
logo$.next('fish');

color$.next('green');
logo$.next('dog');

color$.next('red');
logo$.next('bird');

color$.next('blue');

// 5. When the two persons(observables) has no more info, they said bye bye.. We will write code here later
...

I guess the code above is pretty expressive itself. We created two observables by using Subject. For part 4 in the code, every .next(<value>) means Ms. Color or Mr. Logo is picking color or logo.

我猜上面的代码本身就很具有表现力。 我们使用Subject创建了两个可观察对象。 对于代码的第4部分,每个.next(<value>)表示Color女士或Logo先生正在选择颜色或徽标。

Take note of the sequence of information (part 4 in our code), here is the summary:-

注意信息的顺序(代码的第4部分),以下是摘要:

sequence of info

1. Ms. Color picks WHITE
2. Mr. Logo picks FISH
3. Ms. Color picks GREEN
4. Mr. Logo picks DOG
5. Ms. Color picks RED
6. Mr. Logo picks BIRD
7. Ms. Color picks BLUE

Later, we will update our code (part 3 & 5) to subscribe to both color and logo observables using the 4 different operators to see how the shirts are produced differently.

稍后,我们将更新代码(第3部分和第5部分),以使用4个不同的运算符订阅可观察到的颜色和徽标,以查看衬衫的生产方式是否不同。

All set. Let's start exploring our first operator!

可以了,好了。 让我们开始探索我们的第一个操作员!

zip-爱情鸟运算符 ( zip - the love birds operator )

I call zip operator the love birds operator. Love birds need to always be together. Remember Titanic, the "you jump, I jump" type.

我称zip算子为爱情鸟算子。 爱情鸟需要永远在一起。 记住泰坦尼克号的“你跳,我跳”类型。

Let's replace our code (part 3) with below:

让我们用以下代码替换我们的代码(第3部分):

// 3. We are ready to start printing shirt...
zip(color$, logo$)
    .subscribe(([color, logo]) => console.log(`${color} shirt with ${logo}`));

TL; DR (TL;DR)

For those of you who are not familar with JavaScript ES6/ES2015 destructuring assignment, you might find the syntax in subscribe [color, logo] a little bit odd.

对于不熟悉JavaScript ES6 / ES2015 解构分配的人员 ,您可能会发现subscription [color, logo]的语法有些奇怪。

When we zip color$ and logo$, we expect to receive an array of 2 items during subscribe, first item is color and second is logo (follow their orders in zip function).

当我们拉链color$logo$ ,我们预计在收到的2项的数组subscribe ,第一项是color和第二是logo (按照他们的订单zip功能)。

The traditional way of writing it would be .subscribe((data) => console.log(${data[0]} shirt with ${data[1]})). As you can see, it's not very obvious that data[0] is color.

传统的编写方式是.subscribe((data) => console.log( $ {data [0]}衬衫和$ {data [1]} )) 。 如您所见, data[0]是彩色的并不太明显。

ES6 allows us to unpack the value from arrays. Therefore, we unpack data into [color, logo] straight away. More readable right?

ES6允许我们从数组中解压缩值。 因此,我们立即将data解压缩为[color, logo] 。 更具可读性吧?

结果 (Result)

Alright, let's go back to our code and run it. The shirt printing result would be:-

好了,让我们回到我们的代码并运行它。 衬衫的印刷结果为:-

zip - printed shirts

Here is what get to log in the console:

以下是登录控制台的内容:

1. white shirt with fish
2. green shirt with dog
3. red shirt with bird

zip如何工作? (How does zip work?)

Again, zip operator is the love birds operator. In our case, color will wait for logo whenever there are new value (vice versa). Both values must change then only the log gets triggered.

同样, zip运算符是爱情鸟运算符。 在我们的案例中,只要有新值, color就会等待logo (反之亦然)。 两个值都必须更改,然后才触发日志。

1. Ms. Color picks WHITE
2. Mr. Logo picks FISH <- log 01, WHITE + FISH in pair, love birds!
3. Ms. Color picks GREEN
4. Mr. Logo picks DOG <- log 02, GREEN + DOG in pair, love birds!
5. Ms. Color picks RED
6. Mr. Logo picks BIRD <- log 03, RED + BIRD in pair love birds!
7. Ms. Color picks BLUE <- waiting for love...

zip operator can accept more than 2 observables - no matter how many observables, they must all wait for each other, no man left behind!

zip运算符可以接受2个以上的可观察对象-不管有多少个可观察对象,它们都必须彼此等待,没有人留下!

CombineLatest-Go荷兰运营商 ( combineLatest - the go dutch operator )

I call combineLatest operator the go dutch operator. They are independent and doesn't wait for each other, they take care of themselves.

我称combineLatest运算符为go荷兰运算符。 他们是独立的,不会互相等待,他们会照顾自己。

Let's replace the setup code part 3 with the below code:

让我们用下面的代码替换安装代码第3部分:

// 3. We are ready to start printing shirt...
combineLatest(color$, logo$)
    .subscribe(([color, logo]) => console.log(`${color} shirt with ${logo}`));

The shirt printing result would be:-

衬衫的印刷结果为:-

combinedLatest - printed shirts

Here is what get to log in the console:

以下是登录控制台的内容:

1. white shirt with fish
2. green shirt with fish
3. green shirt with dog
4. red shirt with dog
5. red shirt with bird
6. blue shirt with bird

combineLatest如何工作? (How does combineLatest work?)

As mentioned, combineLatest is the go dutch operator - once they meet their mates one time, they will wait for no man. In our case, first function is triggered after both color and logo values change. There onwards, either color or logo value changed will trigger the log.

如前所述, combineLatest是荷兰人的经营者-一旦他们与伴侣相遇一次,他们将等不及任何人。 在我们的案例中,第一个功能在colorlogo值都更改后触发。 从此以后,更改colorlogo值将触发日志。

1. Ms. Color picks WHITE 
2. Mr. Logo picks FISH <- log 01, color + logo first meet, let's go dutch!
3. Ms. Color picks GREEN <- log 02, GREEN + FISH
4. Mr. Logo picks DOG <- log 03, DOG + GREEN
5. Ms. Color picks RED <- log 04, RED + DOG
6. Mr. Logo picks BIRD <- log 05 BIRD + RED 
7. Ms. Color picks BLUE <- log 06 BLUE + BIRD

withLatestFrom-主从属运算符 ( withLatestFrom - the master slave operator )

I call withLatestFrom operator the master slave operator. At first, master must meet the slave. After that, the master will take the lead, giving command. The slave will just follow and has no voice. :(

我将withLatestFrom运算符称为主从运算符。 首先,主人必须与奴隶见面。 在那之后,主人将领导,指挥。 奴隶只会跟随,没有声音。 :(

Let's replace the setup code part 3 with the below code:

让我们用下面的代码替换安装代码第3部分:

// 3. We are ready to start printing shirt...
color$.pipe(withLatestFrom(logo$))
    .subscribe(([color, logo]) => console.log(`${color} shirt with ${logo}`));

The shirt printing result would be:-

衬衫的印刷结果为:-

withLatestFrom - printed shirts

Here is what get to log in the console:

以下是登录控制台的内容:

1. green shirt with fish
2. red shirt with dog
3. blue shirt with bird

withLatestFrom如何工作? (How does withLatestFrom work?)

Can you guess who is the master and who is the slave in our case?

您能猜出在我们的案例中谁是主人,谁是奴隶?

You guessed it! color is the master while logo is the slave. At first (only once), color(master) will look for logo(slave). Once the logo(slave) has responded, color(master) will take the lead. Log will get triggered whenever the next color(master) value is changed. The logo(slave) value changes will not trigger the console log.

你猜到了! color是主体, logo是从属。 首先(仅一次), color (主color )将查找logo (从属色)。 logo (从属)响应后, color (主)将带头。 每当更改下一个color (主color )值时,日志将被触发。 logo (从属)值更改将不会触发控制台日志。

1. Ms. Color picks WHITE <- nothing happen, waiting for slave
2. Mr. Logo picks FISH <- slave found, wait for the master's command
3. Ms. Color picks GREEN <- log 01, master says GREEN! So, GREEN + FISH
4. Mr. Logo picks DOG
5. Ms. Color picks RED <- log 02, master says RED! So, RED + DOG
6. Mr. Logo picks BIRD
7. Ms. Color picks BLUE <- log 03 master says BLUE! So, BLUE + BIRD

forkJoin-最终目标运算符 ( forkJoin - the final destination operator )

Definitely not the horror movie) kind of final destination! I call forkJoin operator the final destination operator because they are very serious, they only commit once all parties are very sure that they are completely true, final destination of each other.

绝对不是恐怖电影的最终目的地! 我将forkJoin运算符称为最终目标运算符,因为它们非常认真,只有在各方非常确定自己是完全真实的目标时才提交。

Let's replace the setup code part 3 with the below code:

让我们用下面的代码替换安装代码第3部分:

// 3. We are ready to start printing shirt...
forkJoin(color$, logo$)
    .subscribe(([color, logo]) => console.log(`${color} shirt with ${logo}`));

The shirt printing result would be:-

forkJoin - printed shirts

衬衫的印刷结果为:-

You see it right, the result is NOTHING! There is no log in console.

你看它的权利,其结果是什么 ! 没有登录控制台。

forkJoin如何工作? (How does forkJoin work?)

forkJoin is the final destination operator! They are very serious to make sure each other are their final destination. In our code, both color and logo observables are not complete, we can keep pushing value by calling .next - that means they are not serious enough and thus they are not final destination of each other.

forkJoinfinal destination运营商! 他们非常认真地确保彼此是他们的最终目的地。 在我们的代码中, colorlogo可观察性都不完整,我们可以通过调用.next来保持价值,这意味着它们不够认真,因此它们并不是彼此的final destination

那么,我们如何认真? (So, how do we be serious?)

We need to complete both observables. Let's replace our setup code part 5 with the below:

我们需要complete两个可观察项。 让我们用以下代码替换我们的设置代码第5部分:

// 5. When the two persons(observables) ...
color$.complete();
logo$.complete();

Great! With the above code changes, Here is our shirt printing result:-

大! 更改以上代码后,以下是我们的衬衫打印结果:

forkJoin (complete) - printed shirts

Here is what get to log in the console:

以下是登录控制台的内容:

1. blue shirt with bird

Here is the sequence of when the log happens:-

以下是发生日志的时间顺序:

1. Ms. Color picks WHITE
2. Mr. Logo picks FISH
3. Ms. Color picks GREEN
4. Mr. Logo picks DOG
5. Ms. Color picks RED
6. Mr. Logo picks BIRD
7. Ms. Color picks BLUE
8. Ms. Color completed <-- color is serious!
9. Mr. Logo completed <--- log no 01, both logo & color are completed. Final destination!

There is more than one way to complete observable. There are operators that allow you to auto complete observable when conditions met, for example take, takeUntil, first.

完成可观察性的方法不只一种。 有些运算符允许您在满足条件时自动完成可观察的观测,例如taketakeUntilfirst

Let's say, you only want to make 1 shirt, you only need to know the first color and logo, In this case, you don't care about the rest of the info that Ms. Color & Mr. Logo provide. You can make use of take or first operator to achieve auto complete observable once first color and logo emit.

假设您只想制作一件衬衫,只需要知道第一种colorlogo ,在这种情况下,您就不必关心Color女士和Logo先生提供的其余信息。 一旦发出第一个colorlogo就可以利用takefirst运算符实现自动完成的观察。

Let's replace the setup code part 3 with the below code:

让我们用下面的代码替换安装代码第3部分:

// 3. We are ready to start printing shirt...
const firstColor$ = color$.pipe(take(1));
const firstLogo$ = logo$.pipe(first());

forkJoin(firstColor$, firstLogo$)
    .subscribe(([color, logo]) => console.log(`${color} shirt with ${logo}`));

You can remove all the code in part 5 as well, we don't need the two lines .complete() (as previous code) because take and first will auto complete the observable when the condition met.

您也可以删除第5部分中的所有代码,我们不需要两行.complete() (与之前的代码一样),因为条件满足时takefirst将自动完成可观察的对象。

With the above change, you should see a white shirt with fish!

进行上述更改后,您应该会看到一条白色的鱼衬衫

forkjoin (auto complete) - printed shirtst

摘要 ( Summary )

Phew~ this is a pretty long article huh? Here is the summary of all results.

one page answer

ew〜这是一篇很长的文章,对吧? 这是所有结果的摘要。

Let's wrap up! In summary, these 4 operators trigger the next action (subscribe function in our case) in slightly different conditions:

结束吧! 总之,这4个运算符在稍有不同的条件下触发下一个动作(在我们的例子中为预订功能):

  • zip - the love birds, always work as a team, triggers only when all observables return new values

    zip- love birds ,始终作为一个团队工作,仅在所有可观测值返回新值时触发
  • combineLatest - the go dutch, start trigger once all observables return new values, then wait for no man, trigger every time when either observable return new value.

    CombineLatest - go dutch ,一旦所有可观察到的值都返回新值,就开始触发,然后等不及,每次当任一可观察到的值都返回新值时触发。
  • withLatestFrom - the master slave, master first waits for slave, after that, action get triggered every time only when master return new value.

    withLatestFrom- master slave ,主服务器首先等待从服务器,此后,仅当主服务器返回新值时,才会触发操作。
  • forkJoin - the final destination, trigger once when all observables have completed.

    forkJoin- final destination ,当所有可观测值完成时触发一次。
我应该使用哪个运营商? (Which operator should I use?)

So I guess you can answer "which operator should I use?" better now. As a general rule of thumb - choose the one that works for you. In some cases, the outcome of using different operators might be the same (that's why people get confused on which one to use), it would be good to understand the intention of the operator & decide accordingly.

因此,我猜您现在可以更好地回答“ 我应该使用哪个运算符? ”。 作为一般的经验法则,请选择适合您的方法 。 在某些情况下,使用不同的运算符的结果可能是相同的(这就是为什么人们对使用哪个运算符感到困惑),因此最好了解运算符的意图并做出相应的决定。

One of the most common use case of combination operators would be calling a few apis, wait for all results return, then executing next logic. Either forkJoin or zip will work and return same result because api calls are one-time only, auto-completed once result is returned (e.g. Angular httpClient.get).

组合运算符最常见的用例之一是调用一些api,等待所有结果返回,然后执行下一个逻辑forkJoinzip都可以工作并返回相同的结果,因为api调用仅一次,返回结果后自动完成(例如Angular httpClient.get )。

However, by understanding the operators more, forkJoin might be more suitable in this case. It is because we "seriously" want to wait for all http responses to complete before proceed to the next step. zip is intended for observables with multiple emits. In our case, we expect only one emit for each http request. Therefore, I think forkJoin is more appropriate (oh well, either way, your code will run just fine & return the same result, but it's good to know right?).

但是,通过更多地了解运算符,在这种情况下, forkJoin可能会更适合。 这是因为我们“非常”想要在完成下一步之前等待所有http响应完成。 zip适用于具有多个发射的可观察对象。 在我们的情况下,我们希望每个http请求仅发出一个。 因此,我认为forkJoin更合适(哦,无论如何,您的代码将正常运行并返回相同的结果,但是很高兴知道吗?)。

演示版 (Demo)

Alright, here is the final code. Please note that the code is a little bit different from demo because I include the code to draw the UI. Logic and general code structure stay the same though.

好的,这是最终代码。 请注意,该代码与演示有所不同,因为我包括了绘制UI的代码。 逻辑和通用代码结构保持不变。

See the Demo on Stackblitz

参见Stackblitz上的演示

测验! (Quiz!)

As a bonus, let me give you a quiz!

作为奖励,让我给您一个测验!

quiz

Figure out the correct results with the provided code. Feel free to play around with it, and explore different scenarios (add more more observables maybe?)!

用提供的代码找出正确的结果。 随意使用它,并探索不同的场景(也许添加更多可观察的东西?)!

Quiz Answer: Click here for the quiz's answer! (please try yourself first)

测验答案:单击此处获取测验答案! (请先尝试)

That's all. Happy coding!

就这样。 编码愉快!

翻译自: https://scotch.io/tutorials/rxjs-operators-for-dummies-forkjoin-zip-combinelatest-withlatestfrom

forkjoin rxjs

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值