透過觀察序列變化掌握非同步事件處理的利器
RxJS 6 新手入門
多奇數位創意有限公司
技術總監 黃保翕(Will 保哥)
https://blog.miniasp.com
簡介 RxJS
The ReactiveX library for JavaScript.
Reactive Extensions (Rx)
• Reactive Extensions (Rx)
- is a library for composing asynchronous and event-based programs using
observable sequences and LINQ-style query operators.
• ReactiveX
- is a combination of the best ideas from the Observer pattern, the Iterator
pattern, and Functional programming.
• Reactive Programming
- is programming with asynchronous data streams.
• Streams
- are cheap and ubiquitous, anything can be a stream.
- variables, user inputs, properties, caches, data structures, etc.
關於 ReactiveX 用到的設計樣式
• 實作了 觀察者模式 (Observer pattern)
- Design Patterns - Observer Pattern
- Observable - ECMAScript Stage 1 Draft (GitHub)
• 用到了 迭代器模式 ( Iterator pattern )
• 也用到 函式編程 與 集合 等設計樣式
- Functional reactive programming
- 前端工程研究:理解函式編程核心概念與如何進行 JavaScript 函式編程
• 主要目的
有效管理非同步環境下的事件資料!
4
什麼是 RxJS https://rxjs.dev
• 一組可用來處理 非同步 或 事件 的 JavaScript 函式庫
- 非同步
• AJAX / XHR ( XMLHttpRequest ) / fetch API
• Service Worker / Node Stream
• setTimeout / setInterval
• Promise
- 事件
• 各式 DOM 事件 ( click, dblclick, keyup, mousemove, … )
• CSS 動畫事件 ( CSS3 transitionEnd event )
• HTML5 Geolocation / WebSockets / Server Send Events
5
了解 RxJS 的核心概念
• Observable 可觀察的物件
- 代表一組未來即將產生的事件資料 ( 被觀察的物件 )
• Observer 觀察者物件
- 代表一個用來接收「觀察結果」的物件 ( 收到的就是事件資料 )
- 觀察者物件就是一個物件包含 3 個含有回呼函式的屬性 ( next , error , complete )
• Subscription 訂閱物件
- 代表正在執行 Observable/Observer 的執行個體 (可用來取消訂閱)
• Operators 運算子
- 必須擁有函數編程中所定義的 純函數 (pure functions) 特性 ( 沒有副作用的函式 )
- 主要用來處理一系列的事件資料集合
- 常見的運算子包含 map, filter, concat, flatMap , switchMap , …
• Subject 主體物件
- 如同 EventEmitter 一樣,主要用來廣播收到的事件資料給多位 Observer (觀察者)
• Schedulers 排程控制器
- 用來集中管理與調度多重事件之間的資料,以控制事件併發情況 (control concurrency)
RxJS 的版本差異
• RxJS 4
- https://github.com/Reactive-Extensions/RxJS
- 當初由 Microsoft 積極發展的專案,並與社群知名的開元開發者進行協作。
• RxJS 5
- https://github.com/ReactiveX/rxjs/tree/5.x
- 提供比前版 RxJS 更好的執行效能 ( 但 API 設計過於混亂 )
• RxJS 6 (Stable)
- https://github.com/ReactiveX/rxjs/tree/6.x
- 遵循 ECMAScript Observable 標準進行實作 (Observable Spec Proposal)
- 更清楚的 API 設計、更好的 tree-shaking 結果、更模組化的檔案結構
- 提供比前版 RxJS 更清楚的偵錯資訊 (more debuggable call stacks)
- Angular 6+ 採用 RxJS 6 最新版本!
7
RxJS 快速上手
RxJS: Getting Started
快速體驗 RxJS 的運作方式
• 開啟官網 https://rxjs.dev/
• 按下 F12 開啟開發者工具並切換到 Console 頁籤
• 執行以下程式碼
rxjs.interval(500)
.pipe(rxjs.operators.take(4))
.subscribe(console.log)
9
建立運算子 (Creation)
過濾運算子 (Filtering)
觀察者 (Observer)
回傳訂閱物件 (Subscription)
透過 ES2015 解構賦值的寫法
const { interval } = rxjs;
const { take } = rxjs.operators;
interval(500)
.pipe(take(4))
.subscribe(console.log)
10
透過 ESM (ES Module) 的寫法
import { interval } from 'rxjs';
import { take } from 'rxjs/operators';
interval(500)
.pipe(take(4))
.subscribe(console.log)
11
快速示範 RxJS 的運作方式
• 建立可觀察的 Observable 物件
var clicks$ = rxjs.fromEvent(document, 'click');
• 建立觀察者物件 ( Observer )
var observer = { next: (x) => console.log(x) };
• 建立訂閱物件 (訂閱 Observable 物件,並傳入 Observer 觀察者物件)
var subs$ = clicks$.subscribe(observer);
• 取消訂閱 Subscription 物件
subs$.unsubscribe();
12
(承上頁) 簡化 Observer 的寫法
• 建立可觀察的 Observable 物件
var clicks$ = rxjs.fromEvent(document, 'click');
• 建立訂閱物件 (訂閱 Observable 物件並自動建立觀察者物件)
var subs$ = clicks$.subscribe(x => console.log(x));
• 取消訂閱 Subscription 物件
subs$.unsubscribe();
13
示範 RxJS 如何透過運算子過濾資料
• 建立可觀察的 Observable 物件
var clicks$ = rxjs.fromEvent(document, 'click');
• 套用 filter 運算子
const { filter } = rxjs.operators;
clicks$ = clicks$.pipe(filter(x => x.clientX < 100));
• 建立訂閱物件 (訂閱 Observable 物件並自動建立觀察者物件)
var subs$ = clicks$.subscribe((x) => console.log(x));
• 取消訂閱 Subscription 物件
subs$.unsubscribe();
14
示範 RxJS 如何套用多個運算子
• 建立可觀察的 Observable 物件
var clicks$ = rxjs.fromEvent(document, 'click');
• 套用 filter 運算子 + 透過 take 運算子取得最多兩個結果
const { filter, take } = rxjs.operators;
clicks$ = clicks$.pipe(
filter(x => x.clientX < 100),
take(2)
);
• 建立訂閱物件 (訂閱 Observable 物件並自動建立觀察者物件)
var subs$ = clicks$.subscribe(x => console.log(x));
• 取消訂閱 Subscription 物件
subs$.unsubscribe();
15
示範 RxJS 主體物件 (Subject) 的用法
• 建立主體物件 ( Subject ) ( 之後要靠這個主體物件進行廣播 )
var subject = new rxjs.Subject();
• 建立可觀察的 Observable 物件
var clicks$ = rxjs.fromEvent(document, 'click');
• 設定最多取得兩個事件資料就將 Observable 物件設為完成
clicks$ = clicks$.pipe(take(2));
• 設定將 clicks$ 全部交由 subject 主體物件進行廣播
clicks$.subscribe(subject);
• 最後再由 subject 去建立 Observer 觀察者物件
var subs1$ = subject.subscribe((x) => console.log(x.clientX));
var subs2$ = subject.subscribe((x) => console.log(x.clientY));
• 取消訂閱 Subscription 物件
subs1$.unsubscribe(); subs2$.unsubscribe();
16
彈珠圖 (Marbles Diagram) - take
17
彈珠圖 (Marbles Diagram) - map
18
彈珠圖 (Marbles Diagram) - concat
19
互動式的彈珠圖 (Marbles Diagram)
20
http://rxmarbles.com/
>>> 畫面上的彈珠是可以拖曳移動的喔! <<<
動畫呈現的彈珠圖 (Marbles Diagram)
21
RxJS Explorer / Launchpad for RxJS
選擇一個 RxJS 運算子
Choose an operator
運算子的分類
• Operator Decision Tree (新版) / Choose an operator (舊版)
- 建立運算子 (Creation Operators)
- 轉換運算子 (Transformation Operators)
- 過濾運算子 (Filtering Operators)
- 組合運算子 (Combination Operators)
- 多播運算子 (Multicasting Operators)
- 錯誤處理運算子 (Error Handling Operators)
- 工具函式運算子 (Utility Operators)
- 條件式與布林運算子 (Conditional and Boolean Operators)
- 數學與彙總運算子 (Mathematical and Aggregate Operators)
23
建立運算子 (Creation Operators)
• 負責建立一個 Observable 物件
• 常用運算子
- from
- fromEvent
- fromEventPattern
- interval
- of
- range
- throwError
- timer
• 其他運算子
- ajax
- bindCallback
- bindNodeCallback
- defer
- empty
- generate
- iif
組合建立運算子 (Join Creation Operators)
• 可將多個 Observable 物件組合成一個 Observable 物件
• 常用運算子
- combineLatest
- concat
- forkJoin
- merge
25
• 其他運算子
- race
- zip
- partition
轉換運算子 (Transformation Operators)
• 負責將 Observable 傳入的資料轉換成另一種格式
• 常用運算子
- concatMap
- concatMapTo
- map
- mapTo
- mergeMap
- mergeMapTo
- switchMap
- switchMapTo
- pluck
• 其他運算子
- buffer
- bufferCount
- bufferTime
- bufferToggle
- bufferWhen
- exhaust
- exhaustMap
- expand
- groupBy
- mergeScan
- pairwise
- partition
- scan
- window
- windowCount
- windowTime
- windowToggle
- windowWhen
過濾運算子 (Filtering Operators)
• 負責將 Observable 傳入的資料過濾/篩選掉
• 常用運算子
- debounce
- debounceTime
- distinct
- filter
- first / last
- skip / take
- throttle
- throttleTime
• 其他運算子
- audit
- auditTime
- distinctUntilChanged
- distinctKey
- distinctUntilKeyChanged
- elementAt
- ignoreElements
- sample
- sampleTime
- single
- skipLast
- skipUntil
- skipWhile
- takeLast
- takeUntil
- takeWhile
組合運算子 (Join Operators)
• 負責組合多個 Observable
• 常用運算子
- combineAll
- concatAll
- mergeAll
- startWith
28
• 其他運算子
- exhaust
- withLatestFrom
多播運算子 (Multicasting Operators)
• 負責將 Observable 廣播給多位觀察者
• 常用運算子
- publish
- publishReplay
- share
29
• 其他運算子
- multicast
- publishBehavior
- publishLast
錯誤處理運算子 (Error Handling Operators)
• 負責處理 Observable 觀察過程中出現的例外錯誤
• 常用運算子
- catchError
- retry
- retryWhen
30
工具函式運算子 (Utility Operators)
• 負責提供 Observable 執行過程的工具函式
• 常用運算子
- tap
- delay
- materialize
- timeout
- timeoutWith
- toArray
31
• 其他運算子
- delayWhen
- dematerialize
- observeOn
- subscribeOn
- timeInterval
- timestamp
條件式與布林運算子 (Conditional and Boolean Operators)
• 負責計算特定條件並回傳布林值的運算子
• 常用運算子
- defaultIfEmpty
- every
- find
- findIndex
- isEmpty
32
數學與彙總運算子 (Mathematical and Aggregate Operators)
• 負責將 Observable 傳來的資料進行數學/彙總運算
• 常用運算子
- count
- max
- min
33
• 其他運算子
- reduce
下一版 RxJS v7 即將廢棄的 APIs
• Deprecations
- Scheduler 建議自行定義類別並實作 SchedulerLike 介面
- empty 建議改用 rxjs.EMPTY 常數
- never 建議改用 rxjs.NEVER 常數
- combineLatest 建議改用 rxjs.combineLatest
- concat 建議改用 rxjs.concat
- merge 建議改用 rxjs.merge
- partition 建議改用 rxjs.partition
- race 建議改用 rxjs.race
- zip 建議改用 rxjs.zip
- ObservableLike 建議改用 InteropObservable
- NotificationKind
RxJS 與 Angular 整合範例
Integration with RxJS and Angular
36
相關連結
• RxJS 官網
• RxJS API 文件
• RxJS 4 API 文件 (舊版文件官網)
• ReactiveX 官網
• 30 天精通 RxJS
• Launchpad for RxJS
• RxMarbles: Interactive diagrams of Rx Observables
37
The Will Will Web
網路世界的學習心得與技術分享
http://blog.miniasp.com/
Facebook
Will 保哥的技術交流中心
http://www.facebook.com/will.fans
Twitter
https://twitter.com/Will_Huang
38
聯絡資訊
THANK YOU!
Q&A

RxJS 6 新手入門

  • 1.
  • 2.
    簡介 RxJS The ReactiveXlibrary for JavaScript.
  • 3.
    Reactive Extensions (Rx) •Reactive Extensions (Rx) - is a library for composing asynchronous and event-based programs using observable sequences and LINQ-style query operators. • ReactiveX - is a combination of the best ideas from the Observer pattern, the Iterator pattern, and Functional programming. • Reactive Programming - is programming with asynchronous data streams. • Streams - are cheap and ubiquitous, anything can be a stream. - variables, user inputs, properties, caches, data structures, etc.
  • 4.
    關於 ReactiveX 用到的設計樣式 •實作了 觀察者模式 (Observer pattern) - Design Patterns - Observer Pattern - Observable - ECMAScript Stage 1 Draft (GitHub) • 用到了 迭代器模式 ( Iterator pattern ) • 也用到 函式編程 與 集合 等設計樣式 - Functional reactive programming - 前端工程研究:理解函式編程核心概念與如何進行 JavaScript 函式編程 • 主要目的 有效管理非同步環境下的事件資料! 4
  • 5.
    什麼是 RxJS https://rxjs.dev •一組可用來處理 非同步 或 事件 的 JavaScript 函式庫 - 非同步 • AJAX / XHR ( XMLHttpRequest ) / fetch API • Service Worker / Node Stream • setTimeout / setInterval • Promise - 事件 • 各式 DOM 事件 ( click, dblclick, keyup, mousemove, … ) • CSS 動畫事件 ( CSS3 transitionEnd event ) • HTML5 Geolocation / WebSockets / Server Send Events 5
  • 6.
    了解 RxJS 的核心概念 •Observable 可觀察的物件 - 代表一組未來即將產生的事件資料 ( 被觀察的物件 ) • Observer 觀察者物件 - 代表一個用來接收「觀察結果」的物件 ( 收到的就是事件資料 ) - 觀察者物件就是一個物件包含 3 個含有回呼函式的屬性 ( next , error , complete ) • Subscription 訂閱物件 - 代表正在執行 Observable/Observer 的執行個體 (可用來取消訂閱) • Operators 運算子 - 必須擁有函數編程中所定義的 純函數 (pure functions) 特性 ( 沒有副作用的函式 ) - 主要用來處理一系列的事件資料集合 - 常見的運算子包含 map, filter, concat, flatMap , switchMap , … • Subject 主體物件 - 如同 EventEmitter 一樣,主要用來廣播收到的事件資料給多位 Observer (觀察者) • Schedulers 排程控制器 - 用來集中管理與調度多重事件之間的資料,以控制事件併發情況 (control concurrency)
  • 7.
    RxJS 的版本差異 • RxJS4 - https://github.com/Reactive-Extensions/RxJS - 當初由 Microsoft 積極發展的專案,並與社群知名的開元開發者進行協作。 • RxJS 5 - https://github.com/ReactiveX/rxjs/tree/5.x - 提供比前版 RxJS 更好的執行效能 ( 但 API 設計過於混亂 ) • RxJS 6 (Stable) - https://github.com/ReactiveX/rxjs/tree/6.x - 遵循 ECMAScript Observable 標準進行實作 (Observable Spec Proposal) - 更清楚的 API 設計、更好的 tree-shaking 結果、更模組化的檔案結構 - 提供比前版 RxJS 更清楚的偵錯資訊 (more debuggable call stacks) - Angular 6+ 採用 RxJS 6 最新版本! 7
  • 8.
  • 9.
    快速體驗 RxJS 的運作方式 •開啟官網 https://rxjs.dev/ • 按下 F12 開啟開發者工具並切換到 Console 頁籤 • 執行以下程式碼 rxjs.interval(500) .pipe(rxjs.operators.take(4)) .subscribe(console.log) 9 建立運算子 (Creation) 過濾運算子 (Filtering) 觀察者 (Observer) 回傳訂閱物件 (Subscription)
  • 10.
    透過 ES2015 解構賦值的寫法 const{ interval } = rxjs; const { take } = rxjs.operators; interval(500) .pipe(take(4)) .subscribe(console.log) 10
  • 11.
    透過 ESM (ESModule) 的寫法 import { interval } from 'rxjs'; import { take } from 'rxjs/operators'; interval(500) .pipe(take(4)) .subscribe(console.log) 11
  • 12.
    快速示範 RxJS 的運作方式 •建立可觀察的 Observable 物件 var clicks$ = rxjs.fromEvent(document, 'click'); • 建立觀察者物件 ( Observer ) var observer = { next: (x) => console.log(x) }; • 建立訂閱物件 (訂閱 Observable 物件,並傳入 Observer 觀察者物件) var subs$ = clicks$.subscribe(observer); • 取消訂閱 Subscription 物件 subs$.unsubscribe(); 12
  • 13.
    (承上頁) 簡化 Observer的寫法 • 建立可觀察的 Observable 物件 var clicks$ = rxjs.fromEvent(document, 'click'); • 建立訂閱物件 (訂閱 Observable 物件並自動建立觀察者物件) var subs$ = clicks$.subscribe(x => console.log(x)); • 取消訂閱 Subscription 物件 subs$.unsubscribe(); 13
  • 14.
    示範 RxJS 如何透過運算子過濾資料 •建立可觀察的 Observable 物件 var clicks$ = rxjs.fromEvent(document, 'click'); • 套用 filter 運算子 const { filter } = rxjs.operators; clicks$ = clicks$.pipe(filter(x => x.clientX < 100)); • 建立訂閱物件 (訂閱 Observable 物件並自動建立觀察者物件) var subs$ = clicks$.subscribe((x) => console.log(x)); • 取消訂閱 Subscription 物件 subs$.unsubscribe(); 14
  • 15.
    示範 RxJS 如何套用多個運算子 •建立可觀察的 Observable 物件 var clicks$ = rxjs.fromEvent(document, 'click'); • 套用 filter 運算子 + 透過 take 運算子取得最多兩個結果 const { filter, take } = rxjs.operators; clicks$ = clicks$.pipe( filter(x => x.clientX < 100), take(2) ); • 建立訂閱物件 (訂閱 Observable 物件並自動建立觀察者物件) var subs$ = clicks$.subscribe(x => console.log(x)); • 取消訂閱 Subscription 物件 subs$.unsubscribe(); 15
  • 16.
    示範 RxJS 主體物件(Subject) 的用法 • 建立主體物件 ( Subject ) ( 之後要靠這個主體物件進行廣播 ) var subject = new rxjs.Subject(); • 建立可觀察的 Observable 物件 var clicks$ = rxjs.fromEvent(document, 'click'); • 設定最多取得兩個事件資料就將 Observable 物件設為完成 clicks$ = clicks$.pipe(take(2)); • 設定將 clicks$ 全部交由 subject 主體物件進行廣播 clicks$.subscribe(subject); • 最後再由 subject 去建立 Observer 觀察者物件 var subs1$ = subject.subscribe((x) => console.log(x.clientX)); var subs2$ = subject.subscribe((x) => console.log(x.clientY)); • 取消訂閱 Subscription 物件 subs1$.unsubscribe(); subs2$.unsubscribe(); 16
  • 17.
  • 18.
  • 19.
  • 20.
    互動式的彈珠圖 (Marbles Diagram) 20 http://rxmarbles.com/ >>>畫面上的彈珠是可以拖曳移動的喔! <<<
  • 21.
  • 22.
  • 23.
    運算子的分類 • Operator DecisionTree (新版) / Choose an operator (舊版) - 建立運算子 (Creation Operators) - 轉換運算子 (Transformation Operators) - 過濾運算子 (Filtering Operators) - 組合運算子 (Combination Operators) - 多播運算子 (Multicasting Operators) - 錯誤處理運算子 (Error Handling Operators) - 工具函式運算子 (Utility Operators) - 條件式與布林運算子 (Conditional and Boolean Operators) - 數學與彙總運算子 (Mathematical and Aggregate Operators) 23
  • 24.
    建立運算子 (Creation Operators) •負責建立一個 Observable 物件 • 常用運算子 - from - fromEvent - fromEventPattern - interval - of - range - throwError - timer • 其他運算子 - ajax - bindCallback - bindNodeCallback - defer - empty - generate - iif
  • 25.
    組合建立運算子 (Join CreationOperators) • 可將多個 Observable 物件組合成一個 Observable 物件 • 常用運算子 - combineLatest - concat - forkJoin - merge 25 • 其他運算子 - race - zip - partition
  • 26.
    轉換運算子 (Transformation Operators) •負責將 Observable 傳入的資料轉換成另一種格式 • 常用運算子 - concatMap - concatMapTo - map - mapTo - mergeMap - mergeMapTo - switchMap - switchMapTo - pluck • 其他運算子 - buffer - bufferCount - bufferTime - bufferToggle - bufferWhen - exhaust - exhaustMap - expand - groupBy - mergeScan - pairwise - partition - scan - window - windowCount - windowTime - windowToggle - windowWhen
  • 27.
    過濾運算子 (Filtering Operators) •負責將 Observable 傳入的資料過濾/篩選掉 • 常用運算子 - debounce - debounceTime - distinct - filter - first / last - skip / take - throttle - throttleTime • 其他運算子 - audit - auditTime - distinctUntilChanged - distinctKey - distinctUntilKeyChanged - elementAt - ignoreElements - sample - sampleTime - single - skipLast - skipUntil - skipWhile - takeLast - takeUntil - takeWhile
  • 28.
    組合運算子 (Join Operators) •負責組合多個 Observable • 常用運算子 - combineAll - concatAll - mergeAll - startWith 28 • 其他運算子 - exhaust - withLatestFrom
  • 29.
    多播運算子 (Multicasting Operators) •負責將 Observable 廣播給多位觀察者 • 常用運算子 - publish - publishReplay - share 29 • 其他運算子 - multicast - publishBehavior - publishLast
  • 30.
    錯誤處理運算子 (Error HandlingOperators) • 負責處理 Observable 觀察過程中出現的例外錯誤 • 常用運算子 - catchError - retry - retryWhen 30
  • 31.
    工具函式運算子 (Utility Operators) •負責提供 Observable 執行過程的工具函式 • 常用運算子 - tap - delay - materialize - timeout - timeoutWith - toArray 31 • 其他運算子 - delayWhen - dematerialize - observeOn - subscribeOn - timeInterval - timestamp
  • 32.
    條件式與布林運算子 (Conditional andBoolean Operators) • 負責計算特定條件並回傳布林值的運算子 • 常用運算子 - defaultIfEmpty - every - find - findIndex - isEmpty 32
  • 33.
    數學與彙總運算子 (Mathematical andAggregate Operators) • 負責將 Observable 傳來的資料進行數學/彙總運算 • 常用運算子 - count - max - min 33 • 其他運算子 - reduce
  • 34.
    下一版 RxJS v7即將廢棄的 APIs • Deprecations - Scheduler 建議自行定義類別並實作 SchedulerLike 介面 - empty 建議改用 rxjs.EMPTY 常數 - never 建議改用 rxjs.NEVER 常數 - combineLatest 建議改用 rxjs.combineLatest - concat 建議改用 rxjs.concat - merge 建議改用 rxjs.merge - partition 建議改用 rxjs.partition - race 建議改用 rxjs.race - zip 建議改用 rxjs.zip - ObservableLike 建議改用 InteropObservable - NotificationKind
  • 35.
    RxJS 與 Angular整合範例 Integration with RxJS and Angular
  • 36.
  • 37.
    相關連結 • RxJS 官網 •RxJS API 文件 • RxJS 4 API 文件 (舊版文件官網) • ReactiveX 官網 • 30 天精通 RxJS • Launchpad for RxJS • RxMarbles: Interactive diagrams of Rx Observables 37
  • 38.
    The Will WillWeb 網路世界的學習心得與技術分享 http://blog.miniasp.com/ Facebook Will 保哥的技術交流中心 http://www.facebook.com/will.fans Twitter https://twitter.com/Will_Huang 38 聯絡資訊
  • 39.