0%

Rxjs【take, first, takeUntil, concatAll】

Rxjs学习之路

1、小贴士

这篇文章是我的Angular Rxjs Series中的第篇三文章,在继续阅读本文之前,您至少应该熟悉系列中的第一篇基础文章:

Rxjs6都改变了些什么?

Rxjs【Observable】

1
// 图谱
2
// ----- 代表一个Observable
3
// -----X 代表一个Observable有错误发生
4
// -----| 代表一个Observable结束
5
// (1234)| 代表一个同步Observable结束
6
7
// 特别提示:以下的操作符介绍均采用rxjs6的写法!!!

2、take

take就是取前几个元素后就结束
1
/**
2
 * 例如:      interval(1000).pipe(take(4))
3
 * source:    -----0-----1-----2-----3-----4--..
4
 *                      take(4)
5
 * newest     -----0-----1-----2-----3|
6
 */
7
const takeObservable = interval(1000).pipe(
8
    take(4)
9
);
10
takeObservable.subscribe({
11
    next: (value) => { console.log('=====table操作符: ', value); },
12
    error: (err) => { console.log('=====table操作符: Error: ', err); },
13
    complete: () => { console.log('=====table操作符: complete!'); }
14
});

3、first

first就是取第一个元素后结束
1
/**
2
 * 例如:       interval(1000).pipe(first())
3
 * source:     -----0-----1-----2-----3--..
4
 *                      first()
5
 * newest:     -----0|
6
 */
7
const firstObservable = interval(1000).pipe(
8
    first()
9
);
10
firstObservable.subscribe({
11
    next: (value) => { console.log('=====first操作符: ', value); },
12
    error: (err) => { console.log('=====first操作符: Error: ', err); },
13
    complete: () => { console.log('=====first操作符: complete!'); }
14
});

4、takeUntil

takeUntil就是等到某一件事情【Observable形式的】发生的时候,让当前O1bservable 直送出完成(complete)信号
1
/**
2
 * 例如:       interval(1000).pipe(takeUntil(click))
3
 * source:     -----0-----1-----2-----3--..
4
 * click:      --------------------c-----
5
 *                  takeUntil(click)
6
 * newest:     -----0-----1-----2--|
7
 */
8
const clickObservable = fromEvent(
9
    document.getElementById('game'),
10
    'click'
11
);
12
const takeUnitlObservable = interval(1000).pipe(
13
    takeUntil(clickObservable)
14
);
15
takeUnitlObservable.subscribe({
16
    next: (value) => { console.log('=====takeUntil操作符: ', value); },
17
    error: (err) => { console.log('=====takeUntil操作符: Error: ', err); },
18
    complete: () => { console.log('=====takeUntil操作符: complete!'); }
19
});

5、concatAll

有的时候我们的Observable里的元素还是Observable(Observable<Observable<T>>),可以类似数组里边的元素还是数组([[1,2], [3, 4]]),这个时候我们希望是二维变成一维([1, 2, 3, 4]),即:Observable<T>,concatAll就是用来摊平的。
1
/**
2
 * 必须先等前一个observable完成(complete),才会继续下一个
3
 * 例如:Observable里边还是Observable
4
 * click:       ------------c------------c-----...
5
 *                  map(e => of(1,2,3))
6
 * source:      ------------o------------o-----...
7
 *                           \            \
8
 *                            (1,2,3)|     (1,2,3)|
9
 *                  concatAll()
10
 * newest:      ------------(1,2,3)------(1,2,3)--..
11
 */
12
const eventObservable = fromEvent
13
    document.getElementById('egg'),
14
    'click'
15
);
16
const mapObservable = eventObservable.pipe(
17
    map(x => of(1, 2, 3))
18
);
19
const concatAllObservable = mapObservable.pipe(
20
    concatAll()
21
);
22
concatAllObservable.subscribe({
23
    next: (value) => { console.log('=====concatAll操作符: ', value); },
24
    error: (err) => { console.log('=====concatAll操作符: Error: ', err); },
25
    complete: () => { console.log('=====concatAll操作符: complete!'); }
26
});

完整的例子

例子里边有一个拖拉的example,将上一篇文章的map以及本文的takeUntil、concatAll结合起来的综合例子,可以参考
1
import { Component, OnInit, OnDestroy, Renderer2 } from '@angular/core';
2
import { Subscription, interval, fromEvent, of } from 'rxjs';
3
import { take, first, takeUntil, map, concatAll } from 'rxjs/operators';
4
5
@Component({
6
    selector: 'app-rxjs-demo',
7
    template: `
8
        <h3>Rxjs Demo To Study! -- Operators操作符(take, first, takeUntil, concatAll)</h3>
9
        <button (click)="takeHandler()">take</button>
10
        <button class="mgLeft" (click)="firstHandler()">first</button>
11
        <button class="mgLeft" (click)="takeUntilHandler()">takeUntil</button>
12
        <button class="mgLeft" (click)="concatAllHandler()">concatAll</button>
13
        <button class="mgLeft" id="game">click me end Game</button>
14
        <button class="mgLeft" id="egg">click egg</button>
15
        <div class="drag" id="drag">drag me</div>
16
        <app-back></app-back>
17
    `,
18
    styles: [`
19
        .mgLeft {
20
            margin-left: 20px;
21
        }
22
        .drag {
23
            width: 70px;
24
            height: 24px;
25
            font-size: 12px;
26
            text-align: center;
27
            background: #EEE;
28
            line-height: 24px;
29
            cursor: default;
30
            border-radius: 4px;
31
            position: absolute;
32
            left: 580px;
33
            top: 155px;
34
        }
35
    `]
36
})
37
export class RxjsDemoComponent implements OnInit, OnDestroy {
38
    takeSubscription: Subscription;
39
    firstSubscription: Subscription;
40
    takeUnitlSubscription: Subscription;
41
    concatAllSubscription: Subscription;
42
    dragSubscription: Subscription;
43
44
    constructor(
45
        private renderer: Renderer2
46
    ) { }
47
48
    ngOnInit(): void {
49
        // 图谱
50
        // ----- 代表一个Observable
51
        // -----X 代表一个Observable有错误发生
52
        // -----| 代表一个Observable结束
53
        // (1234)| 代表一个同步Observable结束
54
55
        // 简易拖拉
56
        const mouseDown = fromEvent(document.getElementById('drag'), 'mousedown');
57
        const mouseMove = fromEvent(document.body, 'mousemove');
58
        const mouseUp = fromEvent(document.body, 'mouseup');
59
        const drag = mouseDown.pipe(
60
            map(_ => mouseMove.pipe(takeUntil(mouseUp))),
61
            concatAll(),
62
            map((event: MouseEvent) => ({x: event.clientX, y: event.clientY}))
63
        );
64
        this.dragSubscription = drag.subscribe({
65
            next: (value) => {
66
                console.log('=====drag: ', value);
67
                const dragDom = document.getElementById('drag');
68
                console.log('dragDom', dragDom);
69
                // 第一种写法:angular封装
70
                // this.renderer.setStyle(
71
                //     dragDom,
72
                //     'top',
73
                //     `${value.y}px`
74
                // );
75
                // this.renderer.setStyle(
76
                //     dragDom,
77
                //     'left',
78
                //     `${value.x}px`
79
                // );
80
                // 第二种写法:原生JS支持
81
                dragDom.style.left = value.x + 'px';
82
                dragDom.style.top = value.y + 'px';
83
            },
84
            error: (err) => { console.log('=====drag: Error: ', err); },
85
            complete: () => { console.log('=====drag: complete!'); }
86
        });
87
    }
88
89
    takeHandler() {
90
        /**
91
         * 例如:      interval(1000).pipe(take(4))
92
         * source:    -----0-----1-----2-----3-----4--..
93
         *                      take(4)
94
         * newest     -----0-----1-----2-----3|
95
         */
96
        const takeObservable = interval(1000).pipe(take(4));
97
        this.takeSubscription = takeObservable.subscribe({
98
            next: (value) => { console.log('=====table操作符: ', value); },
99
            error: (err) => { console.log('=====table操作符: Error: ', err); },
100
            complete: () => { console.log('=====table操作符: complete!'); }
101
        });
102
    }
103
104
    firstHandler() {
105
        /**
106
         * 例如:       interval(1000).pipe(first())
107
         * source:     -----0-----1-----2-----3--..
108
         *                      first()
109
         * newest:     -----0|
110
         */
111
        const firstObservable = interval(1000).pipe(first());
112
        this.firstSubscription = firstObservable.subscribe({
113
            next: (value) => { console.log('=====first操作符: ', value); },
114
            error: (err) => { console.log('=====first操作符: Error: ', err); },
115
            complete: () => { console.log('=====first操作符: complete!'); }
116
        });
117
    }
118
119
    takeUntilHandler() {
120
        /**
121
         * 例如:       interval(1000).pipe(takeUntil(click))
122
         * source:     -----0-----1-----2-----3--..
123
         * click:      --------------------c-----
124
         *                  takeUntil(click)
125
         * newest:     -----0-----1-----2--|
126
         */
127
        const clickObservable = fromEvent(document.getElementById('game'), 'click');
128
        const takeUnitlObservable = interval(1000).pipe(takeUntil(clickObservable));
129
        this.takeUnitlSubscription =  takeUnitlObservable.subscribe({
130
            next: (value) => { console.log('=====takeUntil操作符: ', value); },
131
            error: (err) => { console.log('=====takeUntil操作符: Error: ', err); },
132
            complete: () => { console.log('=====takeUntil操作符: complete!'); }
133
        });
134
    }
135
136
    concatAllHandler() {
137
        /**
138
         * 必须先等前一个observable完成(complete),才会继续下一个
139
         * 例如:Observable里边还是Observable
140
         * click:       ------------c------------c-----...
141
         *                  map(e => of(1,2,3))
142
         * source:      ------------o------------o-----...
143
         *                           \            \
144
         *                            (1,2,3)|     (1,2,3)|
145
         *                  concatAll()
146
         * newest:      ------------(1,2,3)------(1,2,3)--..
147
         */
148
        const eventObservable = fromEvent(document.getElementById('egg'), 'click');
149
        const mapObservable = eventObservable.pipe(map(x => of(1, 2, 3)));
150
        const concatAllObservable = mapObservable.pipe(concatAll());
151
        this.concatAllSubscription = concatAllObservable.subscribe({
152
            next: (value) => { console.log('=====concatAll操作符: ', value); },
153
            error: (err) => { console.log('=====concatAll操作符: Error: ', err); },
154
            complete: () => { console.log('=====concatAll操作符: complete!'); }
155
        });
156
    }
157
158
    ngOnDestroy() {
159
        if (this.takeSubscription) {
160
            this.takeSubscription.unsubscribe();
161
        }
162
        if (this.firstSubscription) {
163
            this.firstSubscription.unsubscribe();
164
        }
165
        if (this.takeUnitlSubscription) {
166
            this.takeUnitlSubscription.unsubscribe();
167
        }
168
        if (this.concatAllSubscription) {
169
            this.concatAllSubscription.unsubscribe();
170
        }
171
        if (this.dragSubscription) {
172
            this.dragSubscription.unsubscribe();
173
        }
174
    }
175
}

Marble Diagrams【宝珠图】

1. 这个Marble Diagrams【宝珠图】可以很灵活的表现出每个操作符的使用
2. 下面是超链接传送门

Marble Diagrams【宝珠图】