30天学会RxJS
1. 认识RXJS
2. Functional Reactive Programming
所有的 API 都可以透過 RxJS 來處理,就能用同樣的 API 操作 (RxJS 的 API)
- DOM Events
- XMLHttpRequest
- Fetch
- WebSockets
- Server Send Events
- Service Worker
- Node Stream
- Timer
Functional Reactive Programming
簡單說 FRP 是操作隨著時間連續性改變的數值 而 Rx 則比較像是操作隨著時間發出的離散數值
Reactive Programming
簡單來說就是 當變數或資源發生變動時,由變數或資源自動告訴我發生變動了
- 當發生變動 => 非同步:不知道什麼時候會發生變動,反正變動時要跟我說
-
Functional Programming
函式為一等公民 (First Class) _
函式能夠被賦值給變數
- 函式能被當作參數傳入
- 函式能被當作回傳值
Expression, no Statement (I/O)
表達式 是一個運算過程,一定會有返回值,例如執行一個 function
add(1,2)
陳述式 則是表現某個行為,例如一個 賦值給一個變數
a = 1;
由於 Functional Programming 最早就是為了做運算處理不管 I/O,而 Statement 通常都屬於對系統 I/O 的操作,所以 FP 很自然的不會是 Statement。
Pure Function
Pure function 是指 一個 function 給予相同的參數,永遠會回傳相同的返回值,並且沒有任何顯著的副作用(Side Effect)
slice和splite
Side Effect
Side Effect 是指一個 function 做了跟本身運算返回值沒有關係的事,比如說修改某個全域變數,或是修改傳入參數的值,甚至是執行 console.log 都算是 Side Effect。
- 發送 http request
- 在畫面印出值或是 log
- 獲得使用者 input
- Query DOM 物件
Referential transparency
這種不依賴任何外部狀態,只依賴於傳入的參數的特性也稱為 引用透明(Referential transparency)4. 什麼是 Observable ?
Observer Pattern 观察者设计模式
```javascript var egghead = new Producer(); // new 出一個 Producer 實例叫 eggheadclass Producer {constructor() {this.listeners = [];}addListener(listener) {}removeListener(listener) {}notify(message) {}}
function listener1(message) { }
function listener2(message) { }
egghead.addListener(listener1); // 註冊監聽 egghead.addListener(listener2);
egghead.notify(‘A new course!!’) // 當某件事情方法時,執行
<a name="7HfZj"></a>### Iterator Pattern像是自制一个Subject,可以next()```javascript// 原生的 JS 要怎麼建立 iteratorvar arr = [1, 2, 3];var iterator = arr[Symbol.iterator]();iterator.next();// { value: 1, done: false }iterator.next();// { value: 2, done: false }iterator.next();// { value: 3, done: false }iterator.next();// { value: undefined, done: true }
在最後一個元素前: { done: false, value: elem }
在最後一個元素之後: { done: true, value: undefined }
// 自制Iteratorclass IteratorFromArray {constructor(arr) {this._array = arr;this._cursor = 0;}next() {return this._cursor < this._array.length ?{ value: this._array[this._cursor++], done: false } :{ done: true };}}
Observable
Observer 跟 Iterator 有個共通的特性,就是他們都是 漸進式(progressive) 的取得資料,差別只在於 Observer 是生產者(Producer)推送資料(push),而 Iterator 是消費者(Consumer)要求資料(pull)!
Observable 其實就是這兩個 Pattern 思想的結合,Observable 具備生產者推送資料的特性,同時能像序列,擁有序列處理資料的方法(map, filter…)!
5. 建立Observable
一個核心三個重點
核心: Observable 再加上相關的 Operators(map, filter…)
三个重点:
- Observer
- Subject
- Schedulers
Observable和观察者模式的区别
訂閱 Observable 跟 addEventListener 在實作上其實有非常大的不同。雖然在行為上很像,但實際上 Observable 根本沒有管理一個訂閱的清單,這個部份的細節我們留到最後說明! addEventListener 本質上就是 Observer Pattern 的實作,在內部會有一份訂閱清單
观察者模式內部有一份訂閱者的清單,notify时forEaCH依次执行;这份清单中的函数相当于Observer。
Observable不像是观察者模式,而是訂閱时執行一個 function(传入观察者,执行观察者的方法)
// 我們在內部儲存了一份所有的監聽者清單(this.listeners),在要發佈通知時會對逐一的呼叫這份清單的監聽者。constructor() {this.listeners = [];}
var observable = Rx.Observable.create(function(observer) {observer.next('Jerry'); // RxJS 4.x 以前的版本用 onNextobserver.next('Anna');})// 訂閱這個 observableobservable.subscribe(function(value) {console.log(value);})
同步和异步
RxJS 確實主要在處理非同步行為沒錯,但也同時能處理同步行為,像是上面的程式碼就是同步執行的
觀察者 Observer
var observable = Rx.Observable.create(function(observer) {observer.next('Jerry');observer.next('Anna');observer.complete();observer.next('not work');})// 宣告一個觀察者,具備 next, error, complete 三個方法var observer = {next: function(value) {console.log(value);},error: function(error) {console.log(error)},complete: function() {console.log('complete')}}// 用我們定義好的觀察者,來訂閱這個 observableobservable.subscribe(observer)// 或者可以直接把 next, error, complete 三個 function 依序傳入 observable.subscribeobservable.subscribe(value => { console.log(value); },error => { console.log('Error: ', error); },() => { console.log('complete') })
有時候 Observable 會是一個無限的序列,例如 click 事件,這時 complete 方法就有可能永遠不會被呼叫!
unsubscribe
Events observable 盡量不要用
unsubscribe,通常我們會使用takeUntil,在某個事件發生後來完成 Event observable,這個部份我們之後會講到!
6. RxJS (07):Observable Operators & Marble Diagrams
Operator
我們可以透過 create 的方法建立各種 operator。(内置的已够用)
function map(callback) {return Rx.Observable.create((observer) => {return this.subscribe((value) => {try{observer.next(callback(value));} catch(e) {observer.error(e);}},(err) => { observer.error(err); },() => { observer.complete() })})}Rx.Observable.prototype.map = map;var people = Rx.Observable.of('Jerry', 'Anna');var helloPeople = people.map((item) => item + ' Hello~');helloPeople.subscribe(console.log);// Jerry Hello~// Anna Hello~
Marble Diagram
以map为例
