The New Year is just around the corner. Where are you going to celebrate it? I can only write my article and celebrate the New Year at the same time. Let’s see some operators to celebrate the New Year!

Yesterday we talked about throttle and Debounce for performance tuning, but there is another way to tune performance that is distinct.

Operators

distinct

If you are familiar with SQL, you should be familiar with distinct. It can filter out data with the same value and leave only one stroke. RxJS has the same function for DISTINCT

var source = Rx.Observable.from(['a'.'b'.'c'.'a'.'b'])
            .zip(Rx.Observable.interval(300), (x, y) => x);
var example = source.distinct()

example.subscribe({
    next: (value) = > { console.log(value); },
    error: (err) = > { console.log('Error: ' + err); },
    complete: (a)= > { console.log('complete'); }});// a
// b
// c
// completeCopy the code

JSBin | JSFiddle

The Marble Diagram is shown as follows

source : --a--b--c--a--b|
            distinct()
example: --a--b--c------|Copy the code

As you can see from the example above, when using distinct, any duplicate values are filtered out.

Alternatively, we can pass in a selector callback function, which will pass in a received element and return the value we really want to compare, as shown in the following example

var source = Rx.Observable.from([{ value: 'a'}, { value: 'b' }, { value: 'c' }, { value: 'a' }, { value: 'c' }])
            .zip(Rx.Observable.interval(300), (x, y) => x);
var example = source.distinct((x) = > {
    return x.value
});

example.subscribe({
    next: (value) = > { console.log(value); },
    error: (err) = > { console.log('Error: ' + err); },
    complete: (a)= > { console.log('complete'); }});// {value: "a"}
// {value: "b"}
// {value: "c"}
// completeCopy the code

JSBin | JSFiddle

And as you can see here, because source is sending instances, and JS events are matching memory locations, so in this case those instances are never equal, but what we really want to match is the value in the instance, so we can pass in a selector callback, To choose the values that we want to compare.

The distinct callback has changed a lot in the Bate version of RxJS 5, and is now out of date in many articles and teaching on the Internet. Please be careful!

In fact, distinct() creates a Set behind its back, and when it receives an element, it determines whether it has the same value in the Set. If it does not, it stores it in the Set and sends it out. DistinctUntilChanged is recommended as a second parameter to flushes or distinctUntilChanged

Here refers to the Set is actually RxJS own implementation, with ES6 native Set behavior is also consistent, but because ES6 Set support degree is not ideal, so here is a direct JS implementation.

Distinct can pass in the second parameter flushes Observable to clear temporary data, as shown in the following example

var source = Rx.Observable.from(['a'.'b'.'c'.'a'.'c'])
            .zip(Rx.Observable.interval(300), (x, y) => x);
var flushes = Rx.Observable.interval(1300);
var example = source.distinct(null, flushes);

example.subscribe({
    next: (value) = > { console.log(value); },
    error: (err) = > { console.log('Error: ' + err); },
    complete: (a)= > { console.log('complete'); }});// a
// b
// c
// c
// completeCopy the code

JSBin | JSFiddle

This is best represented by the Marble Diagram

source : --a--b--c--a--c|
flushes: ------------0---...
        distinct(null, flushes);
example: --a--b--c-----c|Copy the code

In fact, the flushes Observable empties the distinct ephemeris when it sends out elements, so it starts all the ephemeris from the beginning. In this way, it doesn’t worry about the growing number of ephemeris. Another method is typically used to distinctUntilChanged.

distinctUntilChanged

DistinctUntilChanged will filter out the same elements as distinct, but distinctUntilChanged will only compare to the last element that was sent, not all of them, as shown in the following example

var source = Rx.Observable.from(['a'.'b'.'c'.'c'.'b'])
            .zip(Rx.Observable.interval(300), (x, y) => x);
var example = source.distinctUntilChanged()

example.subscribe({
    next: (value) = > { console.log(value); },
    error: (err) = > { console.log('Error: ' + err); },
    complete: (a)= > { console.log('complete'); }});// a
// b
// c
// b
// completeCopy the code

JSBin | JSFiddle

In this case distinctUntilChanged will only hold one element and compare it to the placeholder element upon receipt. If it is the same, it will not be sent; otherwise, it will replace the placeholder element with the new element just received and send it.

source : --a--b--c--c--b|
            distinctUntilChanged()
example: --a--b--c-----b|Copy the code

As can be seen from the Marble Diagram, the second C was filtered out because the previous one was C, but the last B was not filtered out because it was different from the previous one.

DistinctUntilChanged is more commonly used in development, most commonly when we are doing multi-party synchronization. When we have multiple clients, and each Client has its own state, the Server will notify all clients when another Client needs to change. However, some clients may receive the new state which is actually the same as the last one. At this point we can use distinctUntilChanged to process only messages that are different from the last one, such as multi-party calls or multi-device synchronization.

Today’s summary

Today, I will talk about two distinct methods. These two methods may not be easy to use, but they are indispensable in complex applications, especially when dealing with many people in real-time synchronization. This method is very useful. If you have any questions, feel free to leave a comment below. Thanks!