摘要:形式上比普通函數(shù)直接返回值啰嗦一些。這里和的重要區(qū)別在于,模式下,可以決定什么時候返回值,以及返回幾個值即調(diào)用回調(diào)函數(shù)的次數(shù)。
前言
RxJS 的 Observable 有點難理解,其實 RxJS 相關(guān)的概念都有點難理解。畢竟 RxJS 引入了響應(yīng)式編程這種新的模式,會不習(xí)慣是正常的。不過總得去理解嘛,而認(rèn)識新的事物時,如果能夠參照一個合適的已知事物比對著,會比較容易理解吧。對于 Observable,類比 JS 中的函數(shù),還是比較好的。
開始 封裝先來看一個普通函數(shù)調(diào)用的例子:
function foo() { console.log("process...") } foo() // 輸出: // process...
很簡單,函數(shù) foo() 封裝了一段邏輯(這里只是向控制臺輸出),然后通過調(diào)用函數(shù),函數(shù)執(zhí)行內(nèi)部的邏輯。
再來看 RxJS Observable 的一個例子:
var foo = Rx.Observable.create(() => { console.log("process...") }) foo.subscribe() // 輸出: // process...
上例中,通過 Rx.Observable.create() 來創(chuàng)建 Observable 對象,將同樣將一段代碼邏輯封裝到 Observable 對象 foo 中,然后通過 foo.subscribe() 來執(zhí)行封裝的代碼邏輯。
對于普通函數(shù)和 Observable 對象,封裝的代碼邏輯在每次調(diào)用時都會重新執(zhí)行一次。從這一點來看,Observable 能夠和普通函數(shù)一樣實現(xiàn)封裝代碼進行復(fù)用。
返回值函數(shù)調(diào)用后可以有返回值:
function foo() { console.log("process...") return 42 } console.log(foo()) // 輸出: // process... // 42
Observable 執(zhí)行后也會產(chǎn)生值,不過和函數(shù)直接返回的方式不同,要通過回調(diào)函數(shù)方式獲?。?/p>
var foo = Rx.Observable.create((observer) => { console.log("process...") observer.next(42) }) foo.subscribe(value => console.log(value)) // 輸出: // process... // 42
Observable 對象內(nèi)部是通過 observer.next(42) 這種方式返回值,而調(diào)用方則通過回調(diào)函數(shù)來接收返回的數(shù)據(jù)。形式上比普通函數(shù)直接返回值啰嗦一些。
從調(diào)用方的角度來看,兩個過程分別是:
普通函數(shù):調(diào)用 > 執(zhí)行邏輯 > 返回數(shù)據(jù)
Observable:訂閱(subscribe) > 執(zhí)行邏輯 > 返回數(shù)據(jù)
從獲取返回值方式來看,調(diào)用函數(shù)是一種直接獲取數(shù)據(jù)的模式,從函數(shù)那里“拿”(pull)數(shù)據(jù);而 Observable 訂閱后,是要由 Observable 通過間接調(diào)用回調(diào)函數(shù)的方式,將數(shù)據(jù)“推”(push)給調(diào)用方。
這里 pull 和 push 的重要區(qū)別在于,push 模式下,Observable 可以決定什么時候返回值,以及返回幾個值(即調(diào)用回調(diào)函數(shù)的次數(shù))。
var foo = Rx.Observable.create((observer) => { console.log("process...") observer.next(1) setTimeout(() => observer.next(2), 1000) }) console.log("before") foo.subscribe(value => console.log(value)) console.log("after") // 輸出: // before // process... // 1 // after // 2
上面例子中,Observable 返回了兩個值,第1個值同步返回,第2個值則是過了1秒后異步返回。
也就是說,從返回值來說,Observable 相比普通函數(shù)區(qū)別在于:
可以返回多個值
可以異步返回值
異常處理函數(shù)執(zhí)行可能出現(xiàn)異常情況,例如:
function foo() { console.log("process...") throw new Error("BUG!") }
我們可以捕獲到異常狀態(tài)進行處理:
try { foo() } catch(e) { console.log("error: " + e) }
對于 Observable,也有錯誤處理的機制:
var foo = Rx.Observable.create((observer) => { console.log("process...") observer.error(new Error("BUG!")) }) foo.subscribe( value => console.log(value), e => console.log("error: " + e) )
Observable 的 subscribe() 方法支持傳入額外的回調(diào)函數(shù),用于處理異常情況。和函數(shù)執(zhí)行類似,出現(xiàn)錯誤之后,Observable 就不再繼續(xù)返回數(shù)據(jù)了。
subscribe() 方法還支持另一種形式傳入回調(diào)函數(shù):
foo.subscribe({ next(value) { console.log(value) }, error(e) { console.log("error: " + e) } })
而這種形式下,傳入的對象和 Observable 內(nèi)部執(zhí)行函數(shù)中的 observer 參數(shù)在形式上就比較一致了。
中止執(zhí)行Observable 內(nèi)部的邏輯可以異步多個返回值,甚至返回?zé)o數(shù)個值:
var foo = Rx.Observable.create((observer) => { let i = 0 setInterval(() => observer.next(i++), 1000) }) foo.subscribe(i => console.log(i)) // 輸出: // 0 // 1 // 2 // ...
上面例子中,Observable 對象每隔 1 秒會返回一個值給調(diào)用方。即使調(diào)用方不再需要數(shù)據(jù),仍舊會繼續(xù)通過回調(diào)函數(shù)向調(diào)用推送數(shù)據(jù)。
RxJS 提供了中止 Observable 執(zhí)行的機制:
var foo = Rx.Observable.create((observer) => { console.log("start") let i = 0 let timer = setInterval(() => observer.next(i++), 1000) return () => { clearInterval(timer) console.log("end") } }) var subscription = foo.subscribe(i => console.log(i)) setTimeout(() => subscription.unsubscribe(), 2500) // 輸出: // start // 0 // 1 // 2 // end
subscribe() 方法返回一個訂閱對象(subscription),該對象上的 unsubscribe() 方法用于取消訂閱,也就是中止 Observable 內(nèi)部邏輯的執(zhí)行,停止返回新的數(shù)據(jù)。
對于具體的 Observable 對象是如何中止執(zhí)行,則要由 Observable 在執(zhí)行后返回一個用于中止執(zhí)行的函數(shù),像上面例子中的這種方式。
Observable 執(zhí)行結(jié)束后,會觸發(fā)觀察者的 complete 回調(diào),所以可以這樣:
foo.subscribe({ next(value) { console.log(value) }, complete() { console.log("completed") } })
Observable 的觀察者共有上面三種回調(diào):
next:獲得數(shù)據(jù)
error:處理異常
complete:執(zhí)行結(jié)束
其中 next 可以被多次調(diào)用,error 和 complete 最多只有一個被調(diào)用一次(任意一個被調(diào)用后不再觸發(fā)其他回調(diào))。
數(shù)據(jù)轉(zhuǎn)換對于函數(shù)返回值,有時候我們要轉(zhuǎn)換后再使用,例如:
function foo() { return 1 } console.log(f00() * 2) // 輸出: // 2
對于 Observable 返回的值,也會有類似的情況,不過通常采用下面的方式:
var foo = Rx.Observable.create((observer) => { let i = 0 setInterval(() => observer.next(i++), 1000) }) foo.map(i => i * 2).subscribe(i => console.log(i)) // 輸出: // 0 // 2 // 4 // ...
其實 foo.map() 返回了新的 Observable 對象,上面代碼等價于:
var foo2 = foo.map(i => i * 2) foo2.subscribe(i => console.log(i))
Observable 對象 foo2 被訂閱時執(zhí)行的內(nèi)部邏輯可以簡單視為:
function subscribe(observer) { let mapFn = v => v * 2 foo.subscribe(v => { observer.next(mapFn(v)) }) }
將這種對數(shù)據(jù)的處理和數(shù)組進行比較看看:
var array = [0, 1, 2, 3, 4, 5] array.map(i => i * 2).forEach(i => console.log(i))
是不是有點像?
除了 map() 方法,Observable 還提供了多種轉(zhuǎn)換方法,如 filter() 用于過濾數(shù)據(jù),find() 值返回第一個滿足條件的數(shù)據(jù),reduce() 對數(shù)據(jù)進行累積處理,在執(zhí)行結(jié)束后返回最終的數(shù)據(jù)。這些方法和數(shù)組方法功能是類似的,只不過是對異步返回的數(shù)據(jù)進行處理。還有一些轉(zhuǎn)換方法更加強大,例如可以 debounceTime() 可以在時間維度上對數(shù)據(jù)進行攔截等等。
Observable 的轉(zhuǎn)換方法,本質(zhì)不過是創(chuàng)建了一個新的 Observable,新的 Observable 基于一定的邏輯對原 Observable 的返回值進行轉(zhuǎn)換處理,然后再推送給觀察者。
總結(jié)Observable 就是一個奇怪的函數(shù),它有和函數(shù)類似的東西,例如封裝了一段邏輯,每次調(diào)用時都會重新執(zhí)行邏輯,執(zhí)行有返回數(shù)據(jù)等;也有更特殊的特性,例如數(shù)據(jù)是推送(push)的方式返回給調(diào)用方法,返回值可以是異步,可以返回多個值等。
不過將 Observable 視作特殊函數(shù),至少對于理解 Observable 上是比較有幫助的。
Observable 也被視為 data stream(數(shù)據(jù)流),這是從 Observable 可以返回多個值的角度來看的,而數(shù)據(jù)轉(zhuǎn)換則是基于當(dāng)前數(shù)據(jù)流創(chuàng)建新的數(shù)據(jù)流,例如:
不過上圖看到的只是數(shù)據(jù),而將 Observable 視為特殊函數(shù)時,不應(yīng)該忘了其內(nèi)部邏輯,不然數(shù)據(jù)是怎么產(chǎn)生的呢。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/88703.html
摘要:深入淺出讀書筆記遺留問題的與對應(yīng)的實際場景,以及在編碼中的體現(xiàn)部分測試你對時間的感覺按住我一秒鐘然后松手你的時間毫秒實現(xiàn)重置避免直接觸發(fā)事件,例如在處點擊然后在處實現(xiàn)獲取間隔時間你超過了的用戶的使用主要用來加載靜態(tài)資源,所 RxJS 《深入淺出RxJS》讀書筆記 遺留問題 Observable的HOT與COLD對應(yīng)的實際場景,以及在編碼中的體現(xiàn) chapter1 html部分 測...
摘要:是一個基于可觀測數(shù)據(jù)流在異步編程應(yīng)用中的庫。正如官網(wǎng)所說,是基于觀察者模式,迭代器模式和函數(shù)式編程。它具有時間與事件響應(yīng)的概念。通知不再發(fā)送任何值。和通知可能只會在執(zhí)行期間發(fā)生一次,并且只會執(zhí)行其中的一個。 RxJS是一個基于可觀測數(shù)據(jù)流在異步編程應(yīng)用中的庫。 ReactiveX is a combination of the best ideas fromthe Observer p...
摘要:有哪些新變化于年月日正式發(fā)布,為開發(fā)人員帶來了一些令人興奮的增補和改進。不要移除包,直到你將所有的鏈?zhǔn)讲僮餍薷臑楣艿啦僮鞣? RxJS 6有哪些新變化? RxJs 6于2018年4月24日正式發(fā)布,為開發(fā)人員帶來了一些令人興奮的增補和改進。Ben Lesh, rxJS核心開發(fā)成員,強調(diào): RxJS 6在擁有更小API的同時,帶來了更整潔的引入方式 提供一個npm包,該package可...
摘要:隨著前端應(yīng)用的復(fù)雜度越來越高,如何管理應(yīng)用的數(shù)據(jù)已經(jīng)是一個不可回避的問題。應(yīng)用的數(shù)據(jù)不是只有狀態(tài)的,還有事件異步常量等等。出于以上兩點原因,最終決定基于來設(shè)計一套管理應(yīng)用的狀態(tài)的解決方案。 隨著前端應(yīng)用的復(fù)雜度越來越高,如何管理應(yīng)用的數(shù)據(jù)已經(jīng)是一個不可回避的問題。當(dāng)你面對的是業(yè)務(wù)場景復(fù)雜、需求變動頻繁、各種應(yīng)用數(shù)據(jù)互相關(guān)聯(lián)依賴的大型前端應(yīng)用時,你會如何去管理應(yīng)用的狀態(tài)數(shù)據(jù)呢? 我們認(rèn)為...
摘要:是的縮寫,起源于,是一個基于可觀測數(shù)據(jù)流結(jié)合觀察者模式和迭代器模式的一種異步編程的應(yīng)用庫。是基于觀察者模式和迭代器模式以函數(shù)式編程思維來實現(xiàn)的。學(xué)習(xí)之前我們需要先了解觀察者模式和迭代器模式,還要對流的概念有所認(rèn)識。 RxJS 是 Reactive Extensions for JavaScript 的縮寫,起源于 Reactive Extensions,是一個基于可觀測數(shù)據(jù)流 Stre...
閱讀 3048·2021-09-08 10:43
閱讀 1038·2019-08-30 15:53
閱讀 987·2019-08-30 13:51
閱讀 847·2019-08-29 14:03
閱讀 810·2019-08-26 18:35
閱讀 1240·2019-08-26 13:38
閱讀 1589·2019-08-26 10:34
閱讀 3505·2019-08-26 10:21