數(shù)據(jù)驅(qū)動(dòng)(data-driven
) 是指將傳遞的數(shù)據(jù)和行為進(jìn)行分離晓折。這也是為什么RxJS能夠以相同的范式來(lái)處理不同類型的數(shù)據(jù)源(比如數(shù)組,字符串鳖目,事件狸眼,AJAX請(qǐng)求等等)的核心原理。
- 以數(shù)據(jù)作為中心谢鹊,將數(shù)據(jù)從行為系統(tǒng)中分離出來(lái)算吩,用數(shù)據(jù)去驅(qū)動(dòng)業(yè)務(wù)
- 沒有數(shù)據(jù),行為將不起作用佃扼,數(shù)據(jù)給行為帶來(lái)升級(jí)偎巢,行為響應(yīng)數(shù)據(jù)的變化,而不是等待數(shù)據(jù)的到來(lái)
- 流(stream)只是一個(gè)傳遞過(guò)程松嘶,如果沒有用戶訂閱,或者數(shù)據(jù)傳遞進(jìn)來(lái)挎扰,流將保存閑置狀態(tài)
數(shù)據(jù)生產(chǎn)者 producers
數(shù)據(jù)的產(chǎn)生有不同的原因翠订,這樣造成數(shù)據(jù)源的來(lái)源有很多種情況。
- 生產(chǎn)者有各種各樣的形態(tài)和大小遵倦,
Event Emitter
就是比較常見的一種生產(chǎn)者尽超,它們用于響應(yīng)鼠標(biāo)點(diǎn)擊或者網(wǎng)絡(luò)請(qǐng)求,同時(shí)他們也是基于時(shí)間的數(shù)據(jù)源 - 當(dāng)處理不同類型的數(shù)據(jù)源梧躺,我們應(yīng)當(dāng)自然會(huì)想到使用不同類型的方式來(lái)處理似谁。不如
event emitters
需要使用命名event handlers 來(lái)處理,Promises
需要一個(gè)連續(xù)傳遞的thenable
函數(shù)來(lái)處理掠哥;setTimeout
需要回調(diào)函數(shù)來(lái)處理巩踏;Arrays
需要通過(guò)循環(huán)來(lái)迭代數(shù)據(jù)
但是Rx對(duì)不同類型的數(shù)據(jù)進(jìn)行了包裝處理,這樣我們可以以相同的范式來(lái)處理不同類型的數(shù)據(jù)源续搀,也就是說(shuō)
不同類型的數(shù)據(jù)源在事件驅(qū)動(dòng)(或流驅(qū)動(dòng))的棱鏡下觀察都是一樣的塞琼,
就好比Rx.Observable 是一個(gè)錘子,把其余所有的數(shù)據(jù)類型當(dāng)作釘子
識(shí)別不同類型的數(shù)據(jù)源
數(shù)據(jù)源廣義的可以分為以下幾類:
- Emitted Data
- Static Data
- Generated Data
1.Emitted Data
發(fā)生數(shù)據(jù)是一種外部與系統(tǒng)交互產(chǎn)生的結(jié)果禁舷”肷迹可以來(lái)自與用戶交互毅往,比如點(diǎn)擊鼠標(biāo),也可以是系統(tǒng)事件派近,比如讀取文件攀唯。
比如你請(qǐng)求數(shù)據(jù),未來(lái)某個(gè)時(shí)間點(diǎn)渴丸,你接收到數(shù)據(jù)侯嘀,對(duì)于這種情況, Promises
可能是一個(gè)好的解決方案曙强。
2.static data
靜態(tài)數(shù)據(jù)已經(jīng)存在或者顯示在系統(tǒng)(內(nèi)存)中残拐,比如 array
,string
。人工的單元測(cè)試數(shù)據(jù)就劃分到這一類型數(shù)據(jù)中碟嘴。
3.Generated data
產(chǎn)生的數(shù)據(jù)是指間隔的或最終產(chǎn)生的數(shù)據(jù)溪食,比如時(shí)鐘每小時(shí)都會(huì)報(bào)時(shí)。
比如無(wú)限產(chǎn)生的數(shù)據(jù)娜扇,不可能將其全部存儲(chǔ)在內(nèi)存中错沃,值應(yīng)當(dāng)動(dòng)態(tài)的被創(chuàng)建和產(chǎn)生給需要的使用者。
數(shù)據(jù)類型的劃分
根據(jù)以下2個(gè)維度可以將數(shù)據(jù)劃分為4類:
- 值的多少: 單值(比如數(shù)字)雀瓢, 多值(比如數(shù)組)
- 數(shù)據(jù)的處理方式: 同步的枢析, 還是異步的
1.single-value && synchronous
這是最簡(jiǎn)單的數(shù)據(jù)類型,比如數(shù)字刃麸,一個(gè)對(duì)象醒叁,我們可以通過(guò) Rx.Observable.of
將其轉(zhuǎn)換為一個(gè) Obserable類型。
但是一般處理簡(jiǎn)單類型的數(shù)據(jù)使用Observable,有點(diǎn)殺雞用牛刀的味道泊业,一般只有我們希望將簡(jiǎn)單類型的值和其它類型的流整合在一起時(shí)把沼,才使用Obserable
2.multi-value && synchronous
我們可以將單值集合起來(lái)形成集合,主要是數(shù)組類型吁伺。
我們可以使用 Rx.Obserable.from
將集合類型轉(zhuǎn)換為Obserable類型
3.single-value && asynchronous
對(duì)于異步的情況肯尺,正是RxJS大放異彩的地方靠抑。
對(duì)于異步的情況由捎,我們只能保證到嗎在未來(lái)某個(gè)時(shí)間被處理穆趴,因此,后面的代碼塊不能依賴前面代碼塊的執(zhí)行窟却。
對(duì)于單值異步的情況昼丑,使用 Promises
進(jìn)行處理最好了,在RxJS中可以使用 Rx.Observable.fromPromise()
將promises轉(zhuǎn)換為Observable類型夸赫。
Rx.Observable.fromPromise($.ajax('/data'))
4. multi-value && aynchronous
這種類型的數(shù)據(jù)一般時(shí)間會(huì)作為數(shù)據(jù)來(lái)源的因子矾克。比如DOM事件,不知道未來(lái)什么時(shí)候會(huì)產(chǎn)生。
對(duì)這種數(shù)據(jù)的處理我們需要 混合迭代器和promise模式胁附,通常的處理方式是使用 EventEmitter
進(jìn)行處理酒繁。
RxJS在javascript原有的EventEmitter的基礎(chǔ)上對(duì)其進(jìn)行了改進(jìn)】仄蓿可以使用 Rx.Observable.fromEvent()
將EventEmitter 轉(zhuǎn)換為Observbale類型
PUSH-BASED && PULL-BASE MODEL
迭代器使用的 pull-based
模型州袒, 而RXJS使用的是 push-based
模型。
-
pull-based
對(duì)下面情況是非常擁有的: 當(dāng)我們知道一個(gè)字能從計(jì)算后立即返回時(shí)弓候。對(duì)于不知道值什么時(shí)候返回或者有沒有值返回的情形郎哭,pull-based
模型就失效了,比如鼠標(biāo)點(diǎn)擊菇存,使用者是不知道下一次點(diǎn)擊事件什么時(shí)候反生夸研,或者發(fā)不發(fā)生 -
push-based
模式中,生產(chǎn)者負(fù)責(zé)創(chuàng)建下一個(gè)數(shù)據(jù)依鸥,消費(fèi)者只需要監(jiān)聽新的事件即可
Observable && Observer
被觀察者和觀察者
- 業(yè)務(wù)邏輯亥至,比如值如何產(chǎn)生,怎么被發(fā)送歸屬于Observable,而所有的渲染細(xì)節(jié)贱迟,是否使用插件什么的處理邏輯歸屬于observer中的調(diào)度者
- 要記住姐扮,無(wú)限事件發(fā)送,比如DO事件衣吠,將不會(huì)觸發(fā) complete() 方法茶敏,因此,取消訂閱取決于使用者缚俏,可以采取手動(dòng)取消訂閱或者自動(dòng)取消訂閱機(jī)制
Observable 基本api
被觀察者本質(zhì)上一個(gè)函數(shù)
下面用簡(jiǎn)單的方式來(lái)描述observable
const observable = events => { // 時(shí)間隊(duì)列
const INTERVAL = 1 * 1000;
let schedulerid;
return { // 返回一個(gè)包含 'subscribe' 方法的對(duì)象
subscribe: oberver => { // 接收 observer 對(duì)象作為參數(shù)
schedulerid = setInterval(() => {
if (events.length === 0) { // 如果沒有時(shí)間處理了
observer.complete();
clearInterval(schedulerid);
schedulerid = undefined;
} else { // 如果有事件反生惊搏, 使用 observer.next()方法進(jìn)行處理
observer.next(events.shift());
}
}, INTERVAL);
return {
unsubscribe: () => { // subscribe 方法返回一個(gè)unsubscribe 方法用于取消訂閱
if (schedulerid) {
clearInterval(schedulerid);
}
}
};
}
}
}
總結(jié)
主要將了以下幾個(gè)方面
- RxJS采用了數(shù)據(jù)驅(qū)動(dòng)的方式,數(shù)據(jù)和業(yè)務(wù)邏輯分離
- RxJs對(duì)javascript的EventEmitter進(jìn)行了改進(jìn)忧换,使其可以對(duì)事件進(jìn)行推送
- Push-based 和 Pull-based 方式的差異
- 根據(jù)值的多少和處理方式2個(gè)維度恬惯,將數(shù)據(jù)源劃分為4類
- 簡(jiǎn)單Observable apis的介紹
- Rx.Observable.of()
- Rx.Observable.from()
- Rx.Observable.fromPromise()
- Rx.Observable.fromEvent()
- Observable 和 Observer 之間的關(guān)系簡(jiǎn)單介紹