什么是RxJS?RxJS解決什么樣的問(wèn)題?通過(guò)怎么樣的手段?帶著這些問(wèn)題掐隐,我們便來(lái)學(xué)習(xí)一下RxJS熟丸,本文旨在幫助大家進(jìn)行RxJS的入門(mén)纱兑。
官網(wǎng)上對(duì)以上問(wèn)題進(jìn)行了解釋
RxJS is a library for composing asynchronous and event-based programs by using observable sequences. It provides one core type, the Observable, satellite types (Observer, Schedulers, Subjects) and operators inspired by Array#extras (map, filter, reduce, every, etc) to allow handling asynchronous events as collections
Think of RxJS as Lodash for events
ReactiveX combines the Observer pattern with the Iterator pattern and functional programming with collections to fill the need for an ideal way of managing sequences of events.
這里面可以把握到的幾個(gè)關(guān)鍵詞
asynchronous 異步
observable sequences 可觀測(cè)的序列
observer 觀察者
operators 操作符
array
lodash
observer pattern 觀察者模式
iterator pattern 迭代器模式
因此我們至少可以在字面上得出下面這樣一句話科贬,并且解答以上的一個(gè)問(wèn)題
RxJS是什么
RxJS是一個(gè)JS庫(kù),通過(guò)觀察者模式以及迭代器模式抄罕,實(shí)現(xiàn)了一個(gè)可觀測(cè)的對(duì)象序列并且提供了豐富的運(yùn)算符壶运,來(lái)幫助我們來(lái)處理異步問(wèn)題夺衍,它可以看成用來(lái)處理異步(事件)的lodash
雖然原文用的是events,不過(guò)事件本身就是一種異步現(xiàn)象煎娇,或者我們可以認(rèn)為網(wǎng)絡(luò)請(qǐng)求攀涵,定時(shí)器這些就是在數(shù)據(jù)返回的時(shí)候給出了一個(gè)事件
如果你對(duì)異步的概念不是很理解得話昆烁,可以自行查找資料,筆者也在寫(xiě)一些關(guān)于異步的文章系冗,可以作為參考
lodash是一個(gè)很有名的函數(shù)庫(kù)芯杀,里面提供了非常多的函數(shù),用來(lái)幫助我們處理數(shù)組左腔,字符串,對(duì)象等惧辈。
這句話也稍稍說(shuō)明了RxJS是怎么來(lái)解決異步問(wèn)題的审洞,不過(guò)暫時(shí)還讓人比較難以理解,暫時(shí)把這些概念稍微記一下箱锐,通過(guò)對(duì)比的例子砖第,我們?cè)賮?lái)認(rèn)識(shí)這些概念环肘,同時(shí)我們將會(huì)去探索另外一個(gè)問(wèn)題的答案
RxJS解決了什么問(wèn)題
我們先從一個(gè)很簡(jiǎn)單的需求入手
- 在一個(gè)輸入框里面的內(nèi)容改變后打印出來(lái)改變的內(nèi)容
<input type="text" id="input-test">
原生JS代碼實(shí)現(xiàn)
document.getElementById('input-test')
.addEventListener('input', (e) => {
console.log(e.target.value)
})
RxJS代碼實(shí)現(xiàn)
rxjs.fromEvent(
document.getElementById('input-test'), 'input'
)
.subscribe(e => console.log(e.target.value))
看起來(lái)好像沒(méi)有什么很大的區(qū)別,也沒(méi)有看到RxJS有什么作用鸽捻。
不過(guò)通過(guò)這個(gè)例子我們可以解釋一下上面的一些名詞
rxjs.fromEvent 產(chǎn)生了一個(gè) observable 對(duì)象
subscribe 里面的回調(diào)函數(shù)就是我們常說(shuō)的 observer 觀察者
而subscribe相當(dāng)于觀察者模式里面的訂閱,用來(lái)連接觀察者與被觀察的對(duì)象
這里我們也就可以知道為什么說(shuō)RxJS實(shí)現(xiàn)了觀察者模式团搞。他通過(guò)subscribe函數(shù)將一個(gè)觀察者observer注冊(cè)到了observable里面骨饿,當(dāng)observable中有事件發(fā)生(數(shù)據(jù)產(chǎn)生)的時(shí)候俱济,便會(huì)調(diào)用observer函數(shù)亡脑,執(zhí)行其中的代碼矢渊。
如果RxJS只能做到上面的這些事情,那么其實(shí)也沒(méi)有什么大不了的,畢竟原生的DOM事件本身就是一種觀察者模式的實(shí)現(xiàn)托修,我們?yōu)槭裁匆?huà)蛇添足再引入一個(gè)RxJS呢婆誓?接下來(lái)我們一步步的去復(fù)雜化這個(gè)需求洋幻,看看我們會(huì)遇到什么問(wèn)題靶端,對(duì)于這些問(wèn)題原生的處理與RxJS的處理有什么不同
- 限制300ms防抖
節(jié)流跟防抖我們都不會(huì)很陌生仔役,下面我們分別使用原生代碼以及RxJS來(lái)實(shí)現(xiàn)輸入框的防抖功能
原生JS
let time = null
const interval = 300
document.getElementById('input-test')
.addEventListener('input', (e) => {
time = Date.now()
setTimeout(() => {
if (Date.now() - time > interval) {
console.log(e.target.value)
}
}, interval);
})
RxJS代碼的實(shí)現(xiàn)
const interval = 300
rxjs.fromEvent(
document.getElementById('input-test'), 'input'
).pipe(
rxjs.operators.map(e => e.target.value),
rxjs.operators.debounceTime(interval),
)
.subscribe(e => console.log(e))
這里我們就可以很明顯的感覺(jué)到绸栅,使用RxJS實(shí)現(xiàn)的代碼要明顯的清爽很多。
觀測(cè)原生的代碼页屠,我們可以發(fā)現(xiàn)以下問(wèn)題
- 具有全局變量
- 不可復(fù)用
當(dāng)然以上的兩個(gè)問(wèn)題粹胯,我們可以通過(guò)封裝寫(xiě)一個(gè)函數(shù)來(lái)進(jìn)行解決,或者使用lodash等相關(guān)的庫(kù)辰企,例如
document.getElementById('input-test')
.addEventListener(
'input',
_.debounce(
(e) => console.log('e', e.target.value),
2000
)
)
如果自己去寫(xiě)函數(shù)风纠,那么肯定會(huì)花費(fèi)時(shí)間,單純的需要使用節(jié)流防抖牢贸,lodash也能應(yīng)付竹观,不過(guò)依舊是那句話,RxJS能處理更多。
觀察RxJS的代碼臭增,其重點(diǎn)在于operators 操作符懂酱。而在這里我們接觸了兩個(gè)操作符
- map
- debounceTime
在前面我們提到的關(guān)鍵詞里面有一個(gè)array數(shù)組,而數(shù)組里面也有一個(gè)很常見(jiàn)的方法map誊抛,在這里操作符map跟數(shù)組的map的使用方式是一致的只不過(guò)一個(gè)的目標(biāo)是數(shù)組列牺,而另一個(gè)是observable對(duì)象,其都是對(duì)內(nèi)容進(jìn)行轉(zhuǎn)化拗窃。
而另外一個(gè)就是debounceTime,它跟我們的在lodash中使用的debounce函數(shù)的作用類(lèi)似瞎领,區(qū)別只有名字不一樣,而在RxJS中也有debounce這個(gè)操作符并炮,debounceTime是因?yàn)槲覀冞@種需求太常見(jiàn)了默刚,所以單獨(dú)抽了出來(lái),通過(guò)使用dobounce可以實(shí)現(xiàn)debounceTime逃魄,當(dāng)然RxJS中的debounce遠(yuǎn)比lodash中的dobounce以及自身的debounceTime要強(qiáng)大得多,比如在這個(gè)例子中荤西,可以根據(jù)輸入值的長(zhǎng)度來(lái)設(shè)置不同的dobounce,在我們輸入第一個(gè)字符的時(shí)候伍俘,假如1s內(nèi)我們不進(jìn)行輸入那么就會(huì)進(jìn)行輸出邪锌,但是假如我們?cè)?s內(nèi)輸入了第二個(gè)字符,那么就必須等到2s后才會(huì)進(jìn)行輸出了癌瘾,不過(guò)在實(shí)際的使用過(guò)程中觅丰,最常見(jiàn)的肯定還是debounceTime。
通過(guò)這兩個(gè)操作符妨退,我們可以知道為什么RxJS被稱為異步的lodash,他跟lodash一樣妇萄,提供了非常多的封裝好的操作符(方法),通過(guò)這些操作符可以方便我們對(duì)異步的處理,提高我們的開(kāi)發(fā)效率咬荷,提升我們代碼的可維護(hù)性
上面還有一個(gè)陌生的方法冠句,pipe 管道,這個(gè)并不是操作符而是observable對(duì)象的一個(gè)方法幸乒,他跟我們后面要提到的一個(gè)概念 數(shù)據(jù)流 息息相關(guān),在這里我們先暫時(shí)略過(guò),因?yàn)樵谠缙诘陌姹局?要使用操作符是可以直接進(jìn)行鏈?zhǔn)秸{(diào)用的
observable.map().dobounceTime.xxx.subscribe
在RxJS的v6版本進(jìn)行全面的優(yōu)化,必須通過(guò)pipe來(lái)使用操作符懦底,雖然看起來(lái)麻煩了很多,但是很明顯罕扎,使用pipe進(jìn)行操作符的調(diào)用聚唐,假如我們想對(duì)一堆操作符進(jìn)行組合,我們只需要實(shí)現(xiàn)一個(gè)數(shù)組就好了腔召,而鏈?zhǔn)秸{(diào)用我們則可能需要去改動(dòng)原型之類(lèi)的杆查,并不是很方便,通過(guò)pipe可以更加方便的對(duì)多個(gè)操作符進(jìn)行封裝宴咧。
RxJS可以提供的異步操作符遠(yuǎn)遠(yuǎn)不止一個(gè)dobounceTime,一個(gè)map這么的簡(jiǎn)單,即使像lodash這么有名的庫(kù)根灯,也只是封裝了throttle,dobounce兩個(gè)跟時(shí)間跟異步相關(guān)的函數(shù),而RxJS能做出這么多的操作符是因?yàn)樗驹诹艘粋€(gè)與lodash完全不同的角度來(lái)看待問(wèn)題的。
接下來(lái)我們?cè)偃?fù)雜化我們的例子掺栅,看看我們還會(huì)遇到什么問(wèn)題烙肺,以及RxJS提供了哪些操作符來(lái)解決這些問(wèn)題。
- 增加兩個(gè)輸入框氧卧,必須在三個(gè)輸入框內(nèi)都輸入內(nèi)容以后才會(huì)進(jìn)行打印
html代碼
<input type="text" id="input-test">
<input type="text" id="input-test2">
原生JS代碼
let time = [0, 0]
const interval = 300
const flagArr = [false, false]
let valueArr = ['', '']
const print = (index, e) => {
time[index] = Date.now()
setTimeout(() => {
if (Date.now() - time[index] > interval) {
flagArr[index] = true
valueArr[index] = e.target.value
if (flagArr.every(v => v)) {
console.log(valueArr.join('/'));
}
}
}, interval);
}
document.getElementById('input-test')
.addEventListener('input', (e) => {
print(0, e)
})
document.getElementById('input-test2')
.addEventListener('input', (e) => {
print(1, e)
})
如果說(shuō)前面的代碼還讓你覺(jué)得這都不是事得話桃笙,我覺(jué)得你看到這部分代碼可能多多少少會(huì)有點(diǎn)頭疼了,這里還是已經(jīng)進(jìn)行過(guò)一部分抽象的結(jié)果了沙绝,實(shí)際上我相信很多人會(huì)直接復(fù)制粘貼一遍相關(guān)的內(nèi)容~~
- 四個(gè)全局變量
- 一個(gè)函數(shù)
- 相互交錯(cuò)的代碼
這樣的代碼假如出bug了是比較難定位bug的闪檬。
我們?cè)賮?lái)看看RxJS的代碼實(shí)現(xiàn)
const interval = 300
const operatorList = [
rxjs.operators.map(e => e.target.value),
rxjs.operators.debounceTime(interval),
]
rxjs.combineLatest(
rxjs.fromEvent(
document.getElementById('input-test'), 'input'
).pipe(...operatorList),
rxjs.fromEvent(
document.getElementById('input-test2'), 'input'
).pipe(...operatorList),
).pipe(
rxjs.operators.map(arr => arr.join('/')),
)
.subscribe(e => console.log(e))
至少?gòu)男Ч蟻?lái)看横缔,我們省去了兩個(gè)全局被交叉引用的變量撤逢。
并且更加重要的是,我們將兩個(gè)observable對(duì)象或者說(shuō)兩條數(shù)據(jù)流進(jìn)行了合并,產(chǎn)生了一條新的數(shù)據(jù)流
在這里我們可以看到敲霍,使用RxJS處理有多個(gè)數(shù)據(jù)源扩然,或者說(shuō)事件的產(chǎn)生對(duì)象的情況翻斟,會(huì)變得比較的方便债热。
- 調(diào)用接口,接口返回內(nèi)容舌剂,最終將接口中返回的內(nèi)容打印到div上,注意,此時(shí)的網(wǎng)絡(luò)不穩(wěn)定
這個(gè)看起來(lái)很簡(jiǎn)單婶溯,但是實(shí)際上,因?yàn)榫W(wǎng)絡(luò)是異步的偷霉,那么完全存在迄委,先發(fā)出去的請(qǐng)求后返回的可能,最終導(dǎo)致在頁(yè)面上的顯示不正確类少,在tab頁(yè)上的處理上叙身,就很有可能會(huì)遇到這種情況。
例如簡(jiǎn)書(shū)的關(guān)注界面,在這個(gè)界面我們很快速的點(diǎn)擊左邊兩個(gè)人的頭像硫狞,那么很有可能出現(xiàn)雖然左邊顯示的A,但是右邊顯示B的文章的情況
下面我們分別使用原生JS以及RxJS來(lái)處理這種情況
<input type="text" id="input-test">
<input type="text" id="input-test2">
<div id="text"></div>
給出一個(gè)函數(shù)用來(lái)模擬接口
const getData = (v) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(v + 'test')
}, Math.random() * 3000);
});
}
通過(guò)隨機(jī)函數(shù)我們模擬接口的不穩(wěn)定返回
假如我們是這樣編寫(xiě)處理接口返回的代碼
const print = async (index, e) => {
time[index] = Date.now()
setTimeout(async () => {
if (Date.now() - time[index] > interval) {
flagArr[index] = true
valueArr[index] = e.target.value
if (flagArr.every(v => v)) {
const v = await getData(valueArr.join('/'))
document.getElementById('text').innerHTML = v
}
}
}, interval);
}
那么很明顯信轿,假如某個(gè)接口比它后發(fā)生的接口慢了晃痴,最終將會(huì)造成顯示錯(cuò)誤
所以我們需要添加標(biāo)記物來(lái)對(duì)每個(gè)接口都進(jìn)行記錄
let time = [0, 0]
const interval = 50
const flagArr = [false, false]
let valueArr = ['', '']
let promiseFlag = 0
const print = async (index, e) => {
time[index] = Date.now()
++promiseFlag
let currentPromise = promiseFlag
setTimeout(async () => {
if (Date.now() - time[index] > interval) {
flagArr[index] = true
valueArr[index] = e.target.value
if (flagArr.every(v => v)) {
const v = await getData(valueArr.join('/'))
if (promiseFlag === currentPromise) {
document.getElementById('text').innerHTML = v
}
}
}
}, interval);
}
而RxJS的代碼如何實(shí)現(xiàn)的呢
rxjs.combineLatest(
rxjs.fromEvent(
document.getElementById('input-test'), 'input'
).pipe(...operatorList),
rxjs.fromEvent(
document.getElementById('input-test2'), 'input'
).pipe(...operatorList),
).pipe(
rxjs.operators.map(arr => arr.join('/')),
rxjs.operators.switchMap((v) => getData(v)),
)
.subscribe(v => document.getElementById('text').innerHTML = v)
依舊是一個(gè)操作符搞定的事情,switchMap可以始終獲取最新的數(shù)據(jù)流而不需要我們進(jìn)行自我的標(biāo)記,而switchMap其實(shí)跟我們上面使用的combineLatest同屬于合并類(lèi)的操作符,在我們又接觸到一個(gè)點(diǎn)财忽,Promise對(duì)象是可以轉(zhuǎn)換成為一個(gè)observable對(duì)象的
現(xiàn)在再回過(guò)頭來(lái)看這些代碼倘核,我們可以發(fā)現(xiàn)當(dāng)我們遇到以下幾種情況的時(shí)候是可以考慮一下RxJS的
- 當(dāng)數(shù)據(jù)的來(lái)源有多個(gè)的時(shí)候
- 當(dāng)數(shù)據(jù)處理與事件與時(shí)間有關(guān)的時(shí)候
- 當(dāng)我們覺(jué)得自己的異步代碼不夠優(yōu)雅的時(shí)候
- 當(dāng)我們想對(duì)某些異步操作進(jìn)行封裝的時(shí)候
對(duì)于前兩點(diǎn)我們可以很明顯的看到,使用RxJS在處理這些復(fù)雜的情況可以很方便的進(jìn)行處理定罢,對(duì)異步的支持遠(yuǎn)遠(yuǎn)不止提供了節(jié)流防抖,對(duì)于第三點(diǎn)笤虫,我們可以很明顯的看到旁瘫,使用了RxJS祖凫,我們的代碼的中間變量減少了很多。而第四點(diǎn)酬凳,大家可以思考一下怎么對(duì)上面的代碼進(jìn)行封裝了~看看是原生的代碼好封裝惠况,還是使用了RxJS的代碼好封裝一點(diǎn),上面的功能去掉兩個(gè)輸入框(其實(shí)加上也沒(méi)有什么關(guān)系)很容易就變成了一個(gè)搜索框的需求了。
通過(guò)以上的例子宁仔,我們可以得出RxJS到底能幫助我們做什么稠屠,它確確實(shí)實(shí)是能夠幫助我們解決問(wèn)題的,那么我們的最后一個(gè)問(wèn)題就來(lái)了翎苫。
RxJS是如何幫助我們解決問(wèn)題的
其實(shí)通過(guò)上面的例子的學(xué)習(xí)权埠,相信大家對(duì)操作符有了一個(gè)大概的概念,但是在上面我們還留下了一個(gè)問(wèn)題煎谍,什么是數(shù)據(jù)流
一個(gè)observable對(duì)象就是一個(gè)數(shù)據(jù)流
以上這句話其實(shí)挺廢話的攘蔽,我個(gè)人更加傾向于,數(shù)據(jù)流是加上了時(shí)間的數(shù)組呐粘,而通過(guò)操作符满俗,我們可以得到另外的數(shù)據(jù)流
不過(guò)這樣還是有點(diǎn)抽象,為什么一個(gè)observable對(duì)象就是一個(gè)數(shù)據(jù)流?什么叫做給數(shù)組加上了時(shí)間?
我們以一個(gè)很常見(jiàn)的創(chuàng)建類(lèi)的操作符interval作為例子
import { interval } from "rxjs";
interval(1000).subscribe(x => console.log(x))
這句代碼會(huì)在每1000ms進(jìn)行一次打印
- 1000ms 打印 0
- 2000ms 打印 1
- 3000ms 打印 2
...
以此類(lèi)推,對(duì)這樣的數(shù)據(jù)我們可以畫(huà)一張圖來(lái)進(jìn)行表示
這就是為什么我們稱為數(shù)據(jù)流的原因
相比較于數(shù)組
- 數(shù)組是有長(zhǎng)度的,而數(shù)據(jù)流可以沒(méi)有作岖,也就是說(shuō)數(shù)據(jù)流可以永不完結(jié)
- 對(duì)數(shù)組進(jìn)行的操作同步的,而數(shù)據(jù)流可以是異步的,其實(shí)通過(guò)一些操作符可以產(chǎn)生同步的數(shù)據(jù)流
當(dāng)數(shù)據(jù)產(chǎn)生的數(shù)據(jù)唆垃,就會(huì)傳遞給subscribe中的observer函數(shù),從而執(zhí)行對(duì)應(yīng)的操作,而不同的observable對(duì)象控制數(shù)據(jù)的產(chǎn)生頻率也是不一樣的
上面這種圖被稱為彈珠圖,也有人稱為寶珠圖,通過(guò)這樣的圖片,我們可以很清晰的看到每個(gè)數(shù)據(jù)是在什么時(shí)候產(chǎn)生的痘儡,而彈珠圖也遠(yuǎn)遠(yuǎn)不止如此辕万,我們回答下面這個(gè)問(wèn)題
operator跟pipe是什么?
我們可以這樣理解,數(shù)據(jù)流中的對(duì)象傳入管道pipe,經(jīng)過(guò)operator操作符的作用,最終產(chǎn)生了新的數(shù)據(jù)流
import { interval } from "rxjs";
import { map } from "rxjs/operators";
interval(1000).pipe(
map(x => x * 10)
).subscribe(x => console.log(x))
其對(duì)應(yīng)的彈珠圖如下
(這個(gè)其實(shí)我拿的官網(wǎng)上的圖沉删,對(duì)應(yīng)上面的代碼得話第一個(gè)應(yīng)該是0,第二個(gè)是1以此類(lèi)推,并且沒(méi)有完結(jié)標(biāo)記)
我們可以看到彈珠圖其實(shí)可以是二維的,經(jīng)過(guò)管道以及操作符渐尿,最終產(chǎn)生了新的數(shù)據(jù)流,而observer中接受到的數(shù)據(jù)依舊是新的數(shù)據(jù)流的數(shù)據(jù)了
- 1000ms 0(10)
- 2000ms 10(20)
- 3000ms 30(30)
當(dāng)然也可以通過(guò)更多的操作對(duì)齊進(jìn)行對(duì)應(yīng)的操作
并且,并不是所有的數(shù)據(jù)最后都會(huì)通過(guò)管道丑念,他們有可能被進(jìn)行了過(guò)濾涡戳,比如我們的節(jié)流以及防抖就過(guò)濾掉了很多我們不需要的數(shù)據(jù),而這些數(shù)據(jù)最終出來(lái)以后脯倚,也不見(jiàn)得會(huì)是原來(lái)的樣子了渔彰,他們可能會(huì)被進(jìn)行轉(zhuǎn)化嵌屎,甚至一個(gè)管道可以跟另外一個(gè)數(shù)據(jù)流進(jìn)行合并,最終產(chǎn)生來(lái)自兩個(gè)來(lái)源的數(shù)據(jù),但是對(duì)于我們的觀察者來(lái)說(shuō),他們之關(guān)心當(dāng)數(shù)據(jù)產(chǎn)生的時(shí)候恍涂,要做什么宝惰,這樣就實(shí)現(xiàn)了解耦合。
此外,將復(fù)雜的工作分發(fā)給了不同的操作符,也使得我們的代碼更加的清晰已讀再沧。
其實(shí)加入你實(shí)現(xiàn)過(guò)一次觀察者模式,比如如下的代碼
class Store {
constructor(state) {
this.state = state
this.observers = []
}
getState() {
return this.state
}
setState(state) {
this.state = Object.assign({}, this.state, state)
// 通知觀察者
this._notifyAllObservers()
}
// 應(yīng)該是一個(gè)內(nèi)部方法
_notifyAllObservers() {
this.observers.forEach(observer => {
observer.update(this.state)
})
}
registere(name, update) {
this.observers.push({
name,
update
})
}
unRegistered(name) {
this.observers = this.observers.filter(v => v.name !== name)
}
clear() {
this.observers = []
}
}
就很容易發(fā)現(xiàn)一個(gè)事情,雖然我們對(duì)觀察者模式的描述經(jīng)常是
當(dāng)目標(biāo)對(duì)象的狀態(tài)發(fā)生變化時(shí)尼夺,會(huì)通知所有觀察者對(duì)象,使它們能夠自動(dòng)更新
很像我們平時(shí)的時(shí)候接到電話然后再去決定自己要去做什么炒瘸。但是其實(shí)看實(shí)現(xiàn)我們更加應(yīng)該這樣說(shuō)
告訴一仆人當(dāng)這件事情發(fā)生的時(shí)候你應(yīng)該做什么淤堵,然后讓這個(gè)仆人去被觀察的對(duì)象哪里待著,等到這個(gè)事情發(fā)生的時(shí)候就去做
這里就可以說(shuō)明顷扩,為什么在上文中我們會(huì)寫(xiě)出一個(gè)這么復(fù)雜的回調(diào)函數(shù)出來(lái)拐邪,因?yàn)檫@個(gè)仆人他既需要記錄時(shí)間,有需要調(diào)用接口查看標(biāo)記物隘截,還需要查看其它的東西狀態(tài)(仆人:我太難了),并且因?yàn)槊看问录a(chǎn)生的時(shí)候你都需要?jiǎng)?chuàng)建一個(gè)仆人(observer)扎阶,所以全局變量也就變成必須的東西
而使用RxJS加上操作符,其實(shí)本質(zhì)上還是觀察者模式婶芭,但是我個(gè)人覺(jué)得是對(duì)觀察者模式的一種封裝东臀,其實(shí)我們自己如果去對(duì)上面的內(nèi)容進(jìn)行封裝得話,一些比較挫的辦法就是一個(gè)大的閉包犀农,然后if else,observable內(nèi)部肯定也是一個(gè)大的閉包惰赋。但是RxJS與普通的觀察者模式不同的是,它內(nèi)置了一個(gè)觀察者井赌,我們可以認(rèn)為這個(gè)觀察者就做了一個(gè)事情谤逼,用一個(gè)手機(jī)外面發(fā)短息
也就是說(shuō)我們?cè)戎荒苡靡粋€(gè)仆人去做的事情現(xiàn)在可以分?jǐn)偨o多個(gè)了,一個(gè)仆人用來(lái)判斷時(shí)間是否正確仇穗,一個(gè)用來(lái)判斷接口返回是不是最新的流部,這樣我們的業(yè)務(wù)邏輯就進(jìn)行了解耦合,并且這些仆人還可以多次利用纹坐,使得我們的排列組合更加的自由,而前面我們提到的全局變量這些枝冀,其實(shí)RxJS就以及給我們處理好了,使得我們可以更加去關(guān)注業(yè)務(wù)邏輯耘子,而不是具體的實(shí)現(xiàn)果漾。
那么到這里我們終于知道了前面說(shuō)的
實(shí)現(xiàn)了一個(gè)可觀測(cè)的對(duì)象序列并且提供了豐富的運(yùn)算符
到底是什么意思,他們?yōu)槭裁茨軌驇椭覀兘鉀Q問(wèn)題谷誓。
尾聲
對(duì)于RxJS的學(xué)習(xí)绒障,這篇文章就暫時(shí)講到這里,這篇文章我弱化了RxJS的很多概念捍歪,因?yàn)镽xJS的概念說(shuō)多也不多說(shuō)少也不少户辱,而系統(tǒng)的學(xué)習(xí)得話肯定會(huì)把操作符都過(guò)一遍鸵钝,那么就很容易讓人陷入,這個(gè)操作符在實(shí)際使用中到底有什么作用的困惑之中庐镐,個(gè)人覺(jué)得學(xué)習(xí)一門(mén)新的技術(shù)恩商,一開(kāi)始還是應(yīng)該去了解它到底解決了什么樣子的問(wèn)題,再去一步步深入技術(shù)細(xì)節(jié)會(huì)比較得好
所以最后必逆,只需要你能看到我們現(xiàn)在遇到的一些問(wèn)題怠堪,并且能夠知道RxJS使用了一個(gè)數(shù)據(jù)流的概念加上很多的操作符來(lái)解決這些問(wèn)題,我感覺(jué)這篇文章就差不多了名眉。
不過(guò)在實(shí)際的使用之中粟矿,我并不覺(jué)得,學(xué)習(xí)了RxJS就一定要去使用它璧针,比如lodash中的節(jié)流防抖嚷炉,在vue中其實(shí)并沒(méi)有比RxJS難用,甚至簡(jiǎn)單的場(chǎng)景下完全更加的好用探橱,主要還是看你需不需要它。
學(xué)習(xí)資料以及參考
有興趣可以自行學(xué)習(xí)了
RxJS官網(wǎng)
不管看再多的官網(wǎng)外的知識(shí)绘证,官網(wǎng)的內(nèi)容一般是最準(zhǔn)確的,特別是對(duì)一些操作符的描述
一個(gè)介紹各自操作符的彈珠圖的網(wǎng)站
與官網(wǎng)不同的是隧膏,這個(gè)網(wǎng)站的彈珠圖是動(dòng)態(tài)可以拖動(dòng)的
深入淺出RxJS
雖然是v5的版本,但是也是唯一一本中文的關(guān)于RxJS的出版書(shū)籍嚷那,
30天精通RxJS
一個(gè)臺(tái)灣人寫(xiě)得RxJS教程,都是繁體字胞枕,可以自行搜索一下簡(jiǎn)書(shū)掘金上的簡(jiǎn)體字文章
RxJS官方的資源庫(kù)
其實(shí)是官網(wǎng)的一部分,不過(guò)很多人可能都沒(méi)注意到魏宽,實(shí)在是有點(diǎn)可惜
本文參考代碼
此外,在RxJS的源代碼中也存在很多的exmple實(shí)例
可以進(jìn)行參考