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)

  1. 表達式 是一個運算過程,一定會有返回值,例如執行一個 function

    1. add(1,2)
  2. 陳述式 則是表現某個行為,例如一個 賦值給一個變數

    1. 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 观察者设计模式

    1. class Producer {
    2. constructor() {
    3. this.listeners = [];
    4. }
    5. addListener(listener) {
    6. }
    7. removeListener(listener) {
    8. }
    9. notify(message) {
    10. }
    11. }
    ```javascript var egghead = new Producer(); // new 出一個 Producer 實例叫 egghead

function listener1(message) { }

function listener2(message) { }

egghead.addListener(listener1); // 註冊監聽 egghead.addListener(listener2);

egghead.notify(‘A new course!!’) // 當某件事情方法時,執行

  1. <a name="7HfZj"></a>
  2. ### Iterator Pattern
  3. 像是自制一个Subject,可以next()
  4. ```javascript
  5. // 原生的 JS 要怎麼建立 iterator
  6. var arr = [1, 2, 3];
  7. var iterator = arr[Symbol.iterator]();
  8. iterator.next();
  9. // { value: 1, done: false }
  10. iterator.next();
  11. // { value: 2, done: false }
  12. iterator.next();
  13. // { value: 3, done: false }
  14. iterator.next();
  15. // { value: undefined, done: true }

在最後一個元素前: { done: false, value: elem }
在最後一個元素之後: { done: true, value: undefined }

  1. // 自制Iterator
  2. class IteratorFromArray {
  3. constructor(arr) {
  4. this._array = arr;
  5. this._cursor = 0;
  6. }
  7. next() {
  8. return this._cursor < this._array.length ?
  9. { value: this._array[this._cursor++], done: false } :
  10. { done: true };
  11. }
  12. }

Observable

Observer 跟 Iterator 有個共通的特性,就是他們都是 漸進式(progressive) 的取得資料,差別只在於 Observer 是生產者(Producer)推送資料(push),而 Iterator 是消費者(Consumer)要求資料(pull)!

Observable 其實就是這兩個 Pattern 思想的結合,Observable 具備生產者推送資料的特性,同時能像序列,擁有序列處理資料的方法(map, filter…)!
教程:30天学会RxJS等 - 图1

5. 建立Observable

一個核心三個重點

核心: Observable 再加上相關的 Operators(map, filter…)
三个重点:

  • Observer
  • Subject
  • Schedulers

Observable和观察者模式的区别

訂閱 Observable 跟 addEventListener 在實作上其實有非常大的不同。雖然在行為上很像,但實際上 Observable 根本沒有管理一個訂閱的清單,這個部份的細節我們留到最後說明! addEventListener 本質上就是 Observer Pattern 的實作,在內部會有一份訂閱清單

观察者模式內部有一份訂閱者的清單,notify时forEaCH依次执行;这份清单中的函数相当于Observer。
Observable不像是观察者模式,而是訂閱时執行一個 function(传入观察者,执行观察者的方法)

  1. // 我們在內部儲存了一份所有的監聽者清單(this.listeners),在要發佈通知時會對逐一的呼叫這份清單的監聽者。
  2. constructor() {
  3. this.listeners = [];
  4. }
  1. var observable = Rx.Observable
  2. .create(function(observer) {
  3. observer.next('Jerry'); // RxJS 4.x 以前的版本用 onNext
  4. observer.next('Anna');
  5. })
  6. // 訂閱這個 observable
  7. observable.subscribe(function(value) {
  8. console.log(value);
  9. })

同步和异步

RxJS 確實主要在處理非同步行為沒錯,但也同時能處理同步行為,像是上面的程式碼就是同步執行的

觀察者 Observer

  1. var observable = Rx.Observable
  2. .create(function(observer) {
  3. observer.next('Jerry');
  4. observer.next('Anna');
  5. observer.complete();
  6. observer.next('not work');
  7. })
  8. // 宣告一個觀察者,具備 next, error, complete 三個方法
  9. var observer = {
  10. next: function(value) {
  11. console.log(value);
  12. },
  13. error: function(error) {
  14. console.log(error)
  15. },
  16. complete: function() {
  17. console.log('complete')
  18. }
  19. }
  20. // 用我們定義好的觀察者,來訂閱這個 observable
  21. observable.subscribe(observer)
  22. // 或者可以直接把 next, error, complete 三個 function 依序傳入 observable.subscribe
  23. observable.subscribe(
  24. value => { console.log(value); },
  25. error => { console.log('Error: ', error); },
  26. () => { console.log('complete') }
  27. )

有時候 Observable 會是一個無限的序列,例如 click 事件,這時 complete 方法就有可能永遠不會被呼叫!

unsubscribe

Events observable 盡量不要用 unsubscribe ,通常我們會使用 takeUntil,在某個事件發生後來完成 Event observable,這個部份我們之後會講到!

6. RxJS (07):Observable Operators & Marble Diagrams

Operator

我們可以透過 create 的方法建立各種 operator。(内置的已够用)

  1. function map(callback) {
  2. return Rx.Observable.create((observer) => {
  3. return this.subscribe(
  4. (value) => {
  5. try{
  6. observer.next(callback(value));
  7. } catch(e) {
  8. observer.error(e);
  9. }
  10. },
  11. (err) => { observer.error(err); },
  12. () => { observer.complete() }
  13. )
  14. })
  15. }
  16. Rx.Observable.prototype.map = map;
  17. var people = Rx.Observable.of('Jerry', 'Anna');
  18. var helloPeople = people.map((item) => item + ' Hello~');
  19. helloPeople.subscribe(console.log);
  20. // Jerry Hello~
  21. // Anna Hello~

Marble Diagram

以map为例
image.png

7. 应用实例

scroll和拖动

30 天精通 RxJS (11): 实务范例 - 完整拖拉应用

渔人和Rxjs的故事,这次一定教会你前端必会的Rxjs
RxJS - 封裝程式的藝術