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