Rxjs簡單介紹
RxJS 是 Reactive Extensions for JavaScript 的縮寫。是一個基於可觀測數據流的響應式編程的庫。
它是基於訂閱-發佈模式
、觀察者模式
與迭代器
實現的。
響應式編程
響應式編程是一種面向數據流和變化傳播的編程範式。這意味着可以在編程語言中很方便地表達靜態或動態的數據流,而相關的計算模型會自動將變化的值通過數據流進行傳播。 — 百度百科…
訂閱-發佈
項目中的 bus…
迭代器
所有的迭代器方法都必須有一個next
方法,next返回{value: '', done: 'false || true'}
。
反過來說,實現next方法接口的數據對象都可以稱爲迭代器。
const arr = [1, 2, 3]
const 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: 3, done: true}
核心概念
- Observable(可觀察對象)
- Observer (觀察者)
- subscriber (訂閱)
- Subject (Observable的特殊對象,繼承了Observable)
- operators(內部操作符)
Observable
可被觀察對象,提供三個方法
-
next
返回一個值,觀察者可以接收到 -
error
發佈一個異常的信號 -
complate
發佈一個處理完成的信號
Observer
觀察者,支持三個回調
- next
處理被觀察者發佈的值 - error
處理被觀察者發佈的異常 - complate
處理被觀察者發佈完成的信號
subscriber
訂閱。將觀察者訂閱觀察被觀察者…
Subject
一個特殊的Observable實現,既可以做爲被觀察者又可以作爲觀察者。
因爲Observable被訂閱時,每一個訂閱它的都會獨立運行。
而subject則更像是一個真正的訂閱管理的維護者,它蒐集所有的訂閱者,統一發送給他們。有點類似於dom中的addEventListener
operators
rxjs內部的一些操作數據量的方法工具,比如創建、合併、過濾、轉換等等。
rxjs結合一些操作纔會顯得更加牛逼…
一些簡單的例子
// 使用create創建一個 observable
const source = rxjs.Observable.create(observable => {
observable.next(1)
})
// 訂閱
source.subscribe(v => console.log(v))
// 1
等一下… 上面的代碼如果使用 Promise 寫的話…
const promise = function () {
return new Promise(resolve => resolve(1))
}
promise.then(v => console.log(v))
// 1
// 看着差不多是不是...
但是問題恰恰在於,Promise 只能返回一次就完事了。
const source = rxjs.Observable.create(observable => {
observable.next(1)
observable.next(2)
})
// 訂閱
source.subscribe(v => console.log(v))
// 1
// 2
並且對於失敗後的處理,promise 失敗了結束了,需要主動去調用
getData () {} // ....
getData().catch(_ => {
getData() // ...
})
// rxjs
const { interval, throwError, of } = rxjs
const { mergeMap, retry } = rxjs.operators
// interval 的意思是在指定時間給出一個累加的數字
const source = interval(1000).pipe(mergeMap(val => {
if (val > 5) {
return throwError('大於5了')
}
return of (val + 1)
}), retry(2)) // 這裏大於5後會拋出異常,但是又 retry 了2次
source.subscribe(v => console.log(v))
// 輸出 3遍 1 - 6,然後拋出異常
所以 promise 其實在處理異步中的問題並不是特別的完美。
對於觀察者中 error
與 complate
的回調:
const source = rxjs.Observable.create(observable => {
observable.next(1)
observable.next(2)
observable.complete()
})
source.subscribe({
next (v) {
// ...
},
error () {
// 處理錯誤情況...
},
complete () {
// 完成的情況...
}
})
在一些場景中,往往是需要兩個數據接口組合在一起給視圖層
的。顯然視圖層不適合做數據的組合的,這種情況下:
const a = rxjs.of({a: 1})
const b = rxjs.of({b: 2})
// 將數據流 a 與 b 組合在一起
const c =rxjs.combineLatest(a, b).pipe(rxjs.operators.map(([a, b]) => {
return {...a, ...b}
}))
c.subscribe(v => console.log(v))
// {a: 1, b: 2}
過濾的場景:
const { interval } = rxjs
const { filter } = rxjs.operators
// 過濾可以整除2的數據
const source = interval(1000).pipe(filter(val => val % 2 === 0))
source.subscribe(v => console.log(v))
// 0 2 4 6 8...
還有其他一些操作符
- first
- last
- take
- delay
- timeInterval
特別多,不在一一列舉,大概有100個左右?
詳情可以看下這裏https://rxjs.dev/guide/operators
場景分析
一個特別適合的例子,trello。
對於trello面板中展示的數據,可以考慮一下,他們是怎麼去規劃的,如何管理的數據流。
- 卡片的順序處理或者過濾條件
- 任務列表中卡片的數據組合(任務內容、標籤、相關人員等)
- 老數據與新數據的合併處理
這個過程可以反着推一下:
// 假如數據組合完畢了,只需要將數據單獨過濾然後再排序
const result = source.map(filter).map(sort)
// 假如新老數據已經合併完畢
const source = rxjs.combineLatest(task, label, users).pipe(map (...a) => {
// 一堆合併操作
}) //組合數據
const task = rxjs.merge(oldtask, newtask) // 新舊的數據流合併到一起,對於下一層無感知是新還是舊
// label
// users
這樣的數據下一層對上一層的數據都是無感知的,不去關心你是新的還是就的,合併沒合併的,只需在數據流中向下走即可,最後result
遍到了視圖層,直接渲染即可。
關於Scheduler
它相當於rxjs中的調度器,可以改變rx內部時間上的行爲。
調度器 | 目的 |
---|---|
null |
不傳遞任何調度器的話,會以同步遞歸的方式發送通知。用於定時操作或尾遞歸操作。 |
Rx.Scheduler.queue |
當前事件幀中的隊列調度(蹦牀調度器)。用於迭代操作。 |
Rx.Scheduler.asap |
微任務的隊列調度,它使用可用的最快速的傳輸機制,比如 Node.js 的 process.nextTick() 或 Web Worker 的 MessageChannel 或 setTimeout 或其他。用於異步轉換。 |
Rx.Scheduler.async |
使用 setInterval 的調度。用於基於時間的操作符。 |