這是【30天精通 RxJS】的 01 篇破婆,如果還沒(méi)看過(guò) 00 篇可以往這邊走:
30 天精通 RxJS (00): 關(guān)于本系列文章
在網(wǎng)頁(yè)的世界存取任何資源都是非同步(Async)的劳闹,比如說(shuō)我們希望拿到一個(gè)檔案,要先發(fā)送一個(gè)請(qǐng)求耘戚,然后必須等到檔案回來(lái)嗡髓,再執(zhí)行對(duì)這個(gè)檔案的操作。這就是一個(gè)非同步的行為收津,而隨著網(wǎng)頁(yè)需求的複雜化饿这,我們所寫(xiě)的 JavaScript 就有各種針對(duì)非同步行為的寫(xiě)法浊伙,例如使用 callback 或是 Promise 物件甚至是新的語(yǔ)法糖 async/await —— 但隨著應(yīng)用需求愈來(lái)愈複雜,撰寫(xiě)非同步的程式碼仍然非常困難长捧。
非同步常見(jiàn)的問(wèn)題
- 競(jìng)態(tài)條件 (Race Condition)
- 記憶體洩漏 (Memory Leak)
- 複雜的狀態(tài) (Complex State)
- 例外處理 (Exception Handling)
Race Condition
每當(dāng)我們對(duì)同一個(gè)資源同時(shí)做多次的非同步存取時(shí)嚣鄙,就可能發(fā)生 Race Condition 的問(wèn)題。比如說(shuō)我們發(fā)了一個(gè) Request 更新使用者資料串结,然后我們又立即發(fā)送另一個(gè) Request 取得使用者資料哑子,這時(shí)第一個(gè) Request 和第二個(gè) Request 先后順序就會(huì)影響到最終接收到的結(jié)果不同,這就是 Race Condition肌割。
Memory Leak
Memory Leak 是最常被大家忽略的一點(diǎn)卧蜓。原因是在傳統(tǒng)網(wǎng)站的行為,我們每次換頁(yè)都是整頁(yè)重刷把敞,并重新執(zhí)行 JavaScript弥奸,所以不太需要理會(huì)記憶體的問(wèn)題!但是當(dāng)我們希望將網(wǎng)站做得像應(yīng)用程式時(shí)奋早,這件事就變得很重要盛霎。例如做 SPA (Single Page Application) 網(wǎng)站時(shí),我們是透過(guò) JavaScript 來(lái)達(dá)到切換頁(yè)面的內(nèi)容耽装,這時(shí)如果有對(duì) DOM 注冊(cè)監(jiān)聽(tīng)事件愤炸,而沒(méi)有在適當(dāng)?shù)臅r(shí)機(jī)點(diǎn)把監(jiān)聽(tīng)的事件移除,就有可能造成 Memory Leak掉奄。比如說(shuō)在 A 頁(yè)面監(jiān)聽(tīng) body 的 scroll 事件摇幻,但頁(yè)面切換時(shí),沒(méi)有把 scroll 的監(jiān)聽(tīng)事件移除挥萌。
Complex State
當(dāng)有非同步行為時(shí),應(yīng)用程式的狀態(tài)就會(huì)變得非常複雜枉侧!比如說(shuō)我們有一支付費(fèi)用戶才能播放的影片引瀑,首先可能要先抓取這部影片的資訊,接著我們要在播放時(shí)去驗(yàn)證使用者是否有權(quán)限播放榨馁,而使用者也有可能再按下播放后又立即按了取消憨栽,而這些都是非同步執(zhí)行,這時(shí)就會(huì)各種複雜的狀態(tài)需要處理翼虫。
Exception Handling
JavaScript 的 try/catch 可以捕捉同步的例外屑柔,但非同步的程式就沒(méi)這麼容易,尤其當(dāng)我們的非同步行為很複雜時(shí)珍剑,這個(gè)問(wèn)題就愈加明顯掸宛。
各種不同的 API
我們除了要面對(duì)非同步會(huì)遇到的各種問(wèn)題外,還需要煩惱很多不同的 API
- DOM Events
- XMLHttpRequest
- fetch
- WebSockets
- Server Send Events
- Service Worker
- Node Stream
- Timer
上面列的 API 都是非同步的招拙,但他們都有各自的 API 及寫(xiě)法唧瘾!如果我們使用 RxJS措译,上面所有的 API 都可以透過(guò) RxJS 來(lái)處理,就能用同樣的 API 操作 (RxJS 的 API)饰序。
這裡我們舉一個(gè)例子领虹,假如我們想要監(jiān)聽(tīng)點(diǎn)擊事件(click event),但點(diǎn)擊一次之后不再監(jiān)聽(tīng)求豫。
原生 JavaScript
var handler = (e) => {
console.log(e);
document.body.removeEventListener('click', handler); // 結(jié)束監(jiān)聽(tīng)
}
// 注冊(cè)監(jiān)聽(tīng)
document.body.addEventListener('click', handler);
使用 Rx 大概的樣子
Rx.Observable
.fromEvent(document.body, 'click') // 注冊(cè)監(jiān)聽(tīng)
.take(1) // 只取一次
.subscribe(console.log);
JSbin | JSFiddle
(點(diǎn)擊畫(huà)面后會(huì)在 console 顯示塌衰,記得打開(kāi) console 來(lái)看)
大致上能看得出來(lái)我們?cè)谑褂?RxJS 后,不管是針對(duì) DOM Event 還是上面列的各種 API 我們都可以透過(guò) RxJS 的 API 來(lái)做資料操作蝠嘉,像是范例中用 take(n)
來(lái)設(shè)定只取一次最疆,之后就釋放記憶體。
說(shuō)了這麼多是晨,其實(shí)就是簡(jiǎn)單一句話
在面對(duì)日益複雜的問(wèn)題肚菠,我們需要一個(gè)更好的解決方法。
RxJS 基本介紹
RxJS 是一套藉由 Observable sequences 來(lái)組合非同步行為和事件基礎(chǔ)程序的 Library罩缴!
可以把 RxJS 想成處理 非同步行為 的 Lodash蚊逢。
這也被稱為 Functional Reactive Programming,更切確地說(shuō)是指 Functional Programming 及 Reactive Programming 兩個(gè)編程思想的結(jié)合箫章。
RxJS 確實(shí)是 Functional Programming 跟 Reactive Programming 的結(jié)合烙荷,但能不能稱為 Functional Reactive Programming (FRP) 一直有爭(zhēng)議。
Rx 在官網(wǎng)上特別指出檬寂,有時(shí)這會(huì)被稱為 FRP 但這其實(shí)是個(gè)“誤稱”终抽。
簡(jiǎn)單說(shuō) FRP 是操作隨著時(shí)間連續(xù)性改變的數(shù)值 而 Rx 則比較像是操作隨著時(shí)間發(fā)出的離散數(shù)值,這個(gè)部份讀者不用分得太細(xì)桶至,因?yàn)?FRP 的定義及解釋一直存在著歧異昼伴,也有眾多大神為此爭(zhēng)論,如下
André Staltz:Rx 著名的推廣者镣屹,也是 RxJS 5 主要貢獻(xiàn)者之一圃郊,同時(shí)是 Cycle.js 的作者。Staltz 特別寫(xiě)了一篇文章解釋為什麼 Rx 不能說(shuō)是 FRP 但他仍然稱其為 FRP女蜈。
Juan Gomez:曾在 Netflix 工作持舆,目前任職于 Fitbit,經(jīng)常出現(xiàn)在國(guó)外演討會(huì)伪窖,主要寫(xiě) Android逸寓。Juan Gomez 在 Droidcon NYC 2015 的演講中特別提出他堅(jiān)持稱 Rx 為 FRP。
Evan Czaplicki:任職于 NoRedInk覆山,Elm 的作者竹伸。Evan 在 StrangeLoop 2014 的演講中,特別為現(xiàn)在各種 FRP 的不同解釋做分類汹买。
筆者自己的看法是比較偏向直接稱 Rx 為 FRP佩伤,原因是這較為直覺(jué)(FP + RP = FRP)聊倔,也比較不會(huì)對(duì)新手造成困惑,另外就是其他各種編程范式(包含 OOP, FP)其實(shí)都是想法的集合生巡,而非嚴(yán)格的指南(Guideline)耙蔑,我們應(yīng)該更寬鬆的看待 FRP 而不是給他一個(gè)嚴(yán)格的定義。
關(guān)于 Reactive Extension (Rx)
Rx 最早是由微軟開(kāi)發(fā)的 LinQ 擴(kuò)展出來(lái)的開(kāi)源專案孤荣,之后主要由社群的工程師貢獻(xiàn)甸陌,有多種語(yǔ)言支援,也被許多科技公司所採(cǎi)用盐股,如 Netflix, Trello, Github, Airbnb...等钱豁。
Rx 的相關(guān)資訊
- 開(kāi)源專案 (Apache 2.0 License)
- 多種語(yǔ)言支持
- JavaScript
- Java
- C#
- Python
- Ruby
- ...(太多了列不完)
- 官網(wǎng)
微軟目前最成功的開(kāi)源專案
LinQ 唸做 Link,全名是 Language-Integrated Query疯汁,其功能很多元也非常強(qiáng)大牲尺;學(xué) RxJS 可以不用會(huì)。
Functional Reactive Programming
Functional Reactive Programming 是一種編程范式(programming paradigm)幌蚊,白話就是一種寫(xiě)程式的方法論谤碳!舉個(gè)例子,像 OOP 就是一種編程范式溢豆,OOP 告訴我們要使用物件的方式來(lái)思考問(wèn)題蜒简,以及撰寫(xiě)程式。而 Functional Reactive Programming 其實(shí)涵蓋了 Reactive Programming 及 Functional Programming 兩種編程思想漩仙。
Functional Programming
Functional Programming 大部分的人應(yīng)該多少都有接觸過(guò)搓茬,這也是 Rx 學(xué)習(xí)過(guò)程中的重點(diǎn)之一,我們之后會(huì)花兩天的篇幅來(lái)細(xì)講 Functional Programming队他。
如果要用一句話來(lái)總結(jié) Functional Programming卷仑,那就是 用 function 來(lái)思考我們的問(wèn)題,以及撰寫(xiě)程式
在下一篇文章會(huì)更深入的講解 Functional Programming
Reactive Programming
很多人一談到 Reactive Programming 就會(huì)直接聯(lián)想到是在講 RxJS麸折,但實(shí)際上 Reactive Programming 仍是一種編程范式系枪,在不同的場(chǎng)景都有機(jī)會(huì)遇到,而非只存在于 RxJS磕谅,尤雨溪(Vue 的作者)就曾在 twitter 對(duì)此表達(dá)不滿!
Evan You 的推文
Reactive Programming 簡(jiǎn)單來(lái)說(shuō)就是 當(dāng)變數(shù)或資源發(fā)生變動(dòng)時(shí)雾棺,由變數(shù)或資源自動(dòng)告訴我發(fā)生變動(dòng)了
這句話看似簡(jiǎn)單膊夹,其實(shí)背后隱含兩件事
- 當(dāng)發(fā)生變動(dòng) => 非同步:不知道什麼時(shí)候會(huì)發(fā)生變動(dòng),反正變動(dòng)時(shí)要跟我說(shuō)
- 由變數(shù)自動(dòng)告知我 => 我不用寫(xiě)通知我的每一步程式碼
由于最近很紅的 Vue.js 底層就是用 Reactive Programming 的概念實(shí)作捌浩,讓我能很好的舉例放刨,讓大家理解什麼是 Reactive Programming!
當(dāng)我們?cè)谑褂?vue 開(kāi)發(fā)時(shí)尸饺,只要一有綁定的變數(shù)發(fā)生改變进统,相關(guān)的變數(shù)及畫(huà)面也會(huì)跟著變動(dòng)助币,而開(kāi)發(fā)者不需要寫(xiě)這其中如何通知發(fā)生變化的每一步程式碼,只需要專注在發(fā)生變化時(shí)要做什麼事螟碎,這就是典型的 Reactive Programming (記得必須是由變數(shù)或資源主動(dòng)告知眉菱!)
Vue.js 在做 two-ways data binding 是透過(guò) ES5 definedProperty 的 getter/setter。每當(dāng)變數(shù)發(fā)生變動(dòng)時(shí)掉分,就會(huì)執(zhí)行 getter/setter 從而收集有改動(dòng)的變數(shù)俭缓,這也被稱為依賴收集。
Rx 基本上就是上述的兩個(gè)觀念的結(jié)合酥郭,這個(gè)部份讀者在看完之后的文章华坦,會(huì)有更深的體悟。
今日小結(jié)
今天這篇文章主要是帶大家了解為什麼我們需要 RxJS不从,以及 RxJS 的基本介紹惜姐。若讀者還不太能吸收本文的內(nèi)容,可以過(guò)一段時(shí)間后再回來(lái)看這篇文章會(huì)有更深的體會(huì)椿息,或是在下方留言給我歹袁!
文章轉(zhuǎn)自[https://ithelp.ithome.com.tw/articles/10186104]