Rxjs学习之路
1、小贴士
这篇文章是我的Angular Rxjs Series中的第篇三文章,在继续阅读本文之前,您至少应该熟悉系列中的第一篇基础文章:
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 | ({ |
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. 下面是超链接传送门