欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

RxJS的入門指引和初步應(yīng)用

 更新時(shí)間:2019年06月15日 09:48:49   作者:Unknw  
這篇文章主要介紹了RxJS的入門指引和初步應(yīng)用,RxJS是一個(gè)強(qiáng)大的Reactive編程庫(kù),提供了強(qiáng)大的數(shù)據(jù)流組合與控制能力,但是其學(xué)習(xí)門檻一直很高,本次分享期望從一些特別的角度解讀它在業(yè)務(wù)中的使用,而不是從API角度去講解。,需要的朋友可以參考下

前言

RxJS是一個(gè)強(qiáng)大的Reactive編程庫(kù),提供了強(qiáng)大的數(shù)據(jù)流組合與控制能力,但是其學(xué)習(xí)門檻一直很高,本次分享期望從一些特別的角度解讀它在業(yè)務(wù)中的使用,而不是從API角度去講解。

RxJS簡(jiǎn)介

通常,對(duì)RxJS的解釋會(huì)是這么一些東西,我們來(lái)分別看看它們的含義是什么。

  • Reactive
  • Lodash for events
  • Observable
  • Stream-based

什么是Reactive呢,一個(gè)比較直觀的對(duì)比是這樣的:

比如說(shuō),abc三個(gè)變量之間存在加法關(guān)系:

a = b + c

在傳統(tǒng)方式下,這是一種一次性的賦值過(guò)程,調(diào)用一次就結(jié)束了,后面b和c再改變,a也不會(huì)變了。

而在Reactive的理念中,我們定義的不是一次性賦值過(guò)程,而是可重復(fù)的賦值過(guò)程,或者說(shuō)是變量之間的關(guān)系:

a: = b + c

定義出這種關(guān)系之后,每次b或者c產(chǎn)生改變,這個(gè)表達(dá)式都會(huì)被重新計(jì)算。不同的庫(kù)或者語(yǔ)言的實(shí)現(xiàn)機(jī)制可能不同,寫(xiě)法也不完全一樣,但理念是相通的,都是描述出數(shù)據(jù)之間的聯(lián)動(dòng)關(guān)系。

在前端,我們通常有這么一些方式來(lái)處理異步的東西:

  • 回調(diào)
  • 事件
  • Promise
  • Generator

其中,存在兩種處理問(wèn)題的方式,因?yàn)樾枨笠彩莾煞N:

  • 分發(fā)
  • 流程

在處理分發(fā)的需求的時(shí)候,回調(diào)、事件或者類似訂閱發(fā)布這種模式是比較合適的;而在處理流程性質(zhì)的需求時(shí),Promise和Generator比較合適。

在前端,尤其交互很復(fù)雜的系統(tǒng)中,RxJS其實(shí)是要比Generator有優(yōu)勢(shì)的,因?yàn)槌R?jiàn)的每種客戶端開(kāi)發(fā)都是基于事件編程的,對(duì)于事件的處理會(huì)非常多,而一旦系統(tǒng)中大量出現(xiàn)一個(gè)事件要修改視圖的多個(gè)部分(狀態(tài)樹(shù)的多個(gè)位置),分發(fā)關(guān)系就更多了。

RxJS的優(yōu)勢(shì)在于結(jié)合了兩種模式,它的每個(gè)Observable上都能夠訂閱,而Observable之間的關(guān)系,則能夠體現(xiàn)流程(注意,RxJS里面的流程的控制和處理,其直觀性略強(qiáng)于Promise,但弱于Generator)。

我們可以把一切輸入都當(dāng)做數(shù)據(jù)流來(lái)處理,比如說(shuō):

  • 用戶操作
  • 網(wǎng)絡(luò)響應(yīng)
  • 定時(shí)器
  • Worker

RxJS提供了各種API來(lái)創(chuàng)建數(shù)據(jù)流:

  • 單值:of, empty, never
  • 多值:from
  • 定時(shí):interval, timer
  • 從事件創(chuàng)建:fromEvent
  • 從Promise創(chuàng)建:fromPromise
  • 自定義創(chuàng)建:create

創(chuàng)建出來(lái)的數(shù)據(jù)流是一種可觀察的序列,可以被訂閱,也可以被用來(lái)做一些轉(zhuǎn)換操作,比如:

  • 改變數(shù)據(jù)形態(tài):map, mapTo, pluck
  • 過(guò)濾一些值:filter, skip, first, last, take
  • 時(shí)間軸上的操作:delay, timeout, throttle, debounce, audit, bufferTime
  • 累加:reduce, scan
  • 異常處理:throw, catch, retry, finally
  • 條件執(zhí)行:takeUntil, delayWhen, retryWhen, subscribeOn, ObserveOn
  • 轉(zhuǎn)接:switch

也可以對(duì)若干個(gè)數(shù)據(jù)流進(jìn)行組合:

  • concat,保持原來(lái)的序列順序連接兩個(gè)數(shù)據(jù)流
  • merge,合并序列
  • race,預(yù)設(shè)條件為其中一個(gè)數(shù)據(jù)流完成
  • forkJoin,預(yù)設(shè)條件為所有數(shù)據(jù)流都完成
  • zip,取各來(lái)源數(shù)據(jù)流最后一個(gè)值合并為對(duì)象
  • combineLatest,取各來(lái)源數(shù)據(jù)流最后一個(gè)值合并為數(shù)組

這時(shí)候回頭看,其實(shí)RxJS在事件處理的路上已經(jīng)走得太遠(yuǎn)了,從事件到流,它被稱為lodash for events,倒不如說(shuō)是lodash for stream更貼切,它提供的這些操作符也確實(shí)可以跟lodash媲美。

數(shù)據(jù)流這個(gè)詞,很多時(shí)候,是從data-flow翻譯過(guò)來(lái)的,但flow跟stream是不一樣的,我的理解是:flow只關(guān)注一個(gè)大致方向,而stream是受到更嚴(yán)格約束的,它更像是在無(wú)形的管道里面流動(dòng)。

那么,數(shù)據(jù)的管道是什么形狀的?

在RxJS中,存在這么幾種東西:

  • Observable 可觀察序列,只出不進(jìn)
  • Observer 觀察者,只進(jìn)不出
  • Subject 可出可進(jìn)的可觀察序列,可作為觀察者
  • ReplaySubject 帶回放
  • Subscription 訂閱關(guān)系

前三種東西,根據(jù)它們數(shù)據(jù)進(jìn)出的可能性,可以通俗地理解他們的連接方式,這也就是所謂管道的“形狀”,一端密閉一端開(kāi)頭,還是兩端開(kāi)口,都可以用來(lái)輔助記憶。

上面提到的Subscription,則是訂閱之后形成的一個(gè)訂閱關(guān)系,可以用于取消訂閱。

下面,我們通過(guò)一些示例來(lái)大致了解一下RxJS所提供的能力,以及用它進(jìn)行開(kāi)發(fā)所需要的思路轉(zhuǎn)換。

示例一:簡(jiǎn)單的訂閱

很多時(shí)候,我們會(huì)有一些顯示時(shí)間的場(chǎng)景,比如在頁(yè)面下添加評(píng)論,評(píng)論列表中顯示了它們分別是什么時(shí)間創(chuàng)建的,為了含義更清晰,可能我們會(huì)引入moment這樣的庫(kù),把這個(gè)時(shí)間轉(zhuǎn)換為與當(dāng)前時(shí)間的距離:

const diff = moment(createAt).fromNow()

這樣,顯示的時(shí)間就是:一分鐘內(nèi),昨天,上個(gè)月這樣的字樣。

但我們注意到,引入這個(gè)轉(zhuǎn)換是為了增強(qiáng)體驗(yàn),而如果某個(gè)用戶停留在當(dāng)前視圖時(shí)間太長(zhǎng),它的這些信息會(huì)變得不準(zhǔn)確,比如說(shuō),用戶停留了一個(gè)小時(shí),而它看到的信息還顯示:5分鐘之前發(fā)表了評(píng)論,實(shí)際時(shí)間是一個(gè)小時(shí)零5分鐘以前的事了。

從這個(gè)角度看,我們做這個(gè)體驗(yàn)增強(qiáng)的事情只做了一半,不準(zhǔn)確的信息是不能算作增強(qiáng)體驗(yàn)的。

在沒(méi)有RxJS的情況下,我們可能會(huì)通過(guò)一個(gè)定時(shí)器來(lái)做這件事,比如在組件內(nèi)部:

tick() {
this.diff = moment(createAt).fromNow()
setTimeout(tick.bind(this), 1000)
}

但組件并不一定只有一份實(shí)例,這樣,整個(gè)界面上可能就有很多定時(shí)器在同時(shí)跑,這是一種浪費(fèi)。如果要做優(yōu)化,可以把定時(shí)器做成一種服務(wù),把業(yè)務(wù)上需要周期執(zhí)行的東西放進(jìn)去,當(dāng)作定時(shí)任務(wù)來(lái)跑。

如果使用RxJS,可以很容易做到這件事:

Observable.interval(1000).subscribe(() => {
this.diff = moment(createAt).fromNow()
})

示例二:對(duì)時(shí)間軸的操縱

RxJS一個(gè)很強(qiáng)大的特點(diǎn)是,它以流的方式來(lái)對(duì)待數(shù)據(jù),因此,可以用一些操作符對(duì)整個(gè)流上所有的數(shù)據(jù)進(jìn)行延時(shí)、取樣、調(diào)整密集度等等。

const timeA$ = Observable.interval(1000)
const timeB$ = timeA$.filter(num => {
return (num % 2 != 0)
&& (num % 3 != 0)
&& (num % 5 != 0)
&& (num % 7 != 0)
})
const timeC$ = timeB$.debounceTime(3000)
const timeD$ = timeC$.delay(2000)

示例代碼中,我們創(chuàng)建了四個(gè)流:

  • A是由定時(shí)器產(chǎn)生的,每秒一個(gè)值
  • B從A里面過(guò)濾掉了一些
  • C在B的基礎(chǔ)上,對(duì)每?jī)蓚€(gè)間距在3秒之內(nèi)的值進(jìn)行了處理,只留下后一個(gè)值
  • D把C的結(jié)果整體向后平移了2秒

所以結(jié)果大致如下:

A: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
B:    1                                 11       13                  17       19
C:          1                                                  13                             19
D:                 1                                                      13

示例三:我們來(lái)晚了

RxJS還提供了BehaviourSubject和ReplaySubject這樣的東西,用于記錄數(shù)據(jù)流上一些比較重要的信息,讓那些“我們來(lái)晚了”的訂閱者們回放之前錯(cuò)過(guò)的一切。

ReplaySubject可以指定保留的值的個(gè)數(shù),超過(guò)的部分會(huì)被丟棄。

最近新版《射雕英雄傳》比較火,我們來(lái)用代碼描述其中一個(gè)場(chǎng)景。

郭靖和黃蓉一起背書(shū),黃蓉記憶力很好,看了什么,就全部記得;而郭靖屬魚(yú)的,記憶只有七秒,始終只記得背誦的最后三個(gè)字,兩人一起背誦《九陰真經(jīng)》。

代碼實(shí)現(xiàn)如下:

const 九陰真經(jīng) = '天之道,損有余而補(bǔ)不足'
const 黃蓉$ = new ReplaySubject(Number.MAX_VALUE)
const 郭靖$ = new ReplaySubject(3)
const 讀書(shū)$ = Observable.from(九陰真經(jīng).split(''))
讀書(shū)$.subscribe(黃蓉$)
讀書(shū)$.subscribe(郭靖$)

執(zhí)行之后,我們就可以看到,黃蓉背出了所有字,郭靖只記得“補(bǔ)不足”三個(gè)字。

示例四:自動(dòng)更新的狀態(tài)樹(shù)

熟悉Redux的人應(yīng)該會(huì)對(duì)這樣一套理念不陌生:

當(dāng)前視圖狀態(tài) := 之前的狀態(tài) + 本次修改的部分

從一個(gè)應(yīng)用啟動(dòng)之后,整個(gè)全局狀態(tài)的變化,就等于初始的狀態(tài)疊加了之后所有action導(dǎo)致的狀態(tài)修改結(jié)果。

所以這就是一個(gè)典型的reduce操作。在RxJS里面,有一個(gè)scan操作符可以用來(lái)表達(dá)這個(gè)含義,比如說(shuō),我們可以表達(dá)這樣一個(gè)東西:

const action$ = new Subject()
const reducer = (state, payload) => {
// 把payload疊加到state上返回
}
const state$ = action$.scan(reducer)
.startWith({})

只需往這個(gè)action$里面推action,就能夠在state$上獲取出當(dāng)前狀態(tài)。

在Redux里面,會(huì)有一個(gè)東西叫combineReducer,在state比較大的時(shí)候,用不同的reducer修改state的不同的分支,然后合并。如果使用RxJS,也可以很容易表達(dá)出來(lái):

const meAction$ = new Subject()
const meReducer = (state, payload) => {}
const articleAction$ = new Subject()
const articleReducer = (state, payload) => {}
const me$ = meAction$.scan(meReducer).startWith({})
const article$ = articleAction$.scan(articleReducer).startWith({})
const state$ = Observable
.zip(
me$,
article$,
(me, article) => {me, article}
)

借助這樣的機(jī)制,我們實(shí)現(xiàn)了Redux類似的功能,社區(qū)里面也有基于RxJS實(shí)現(xiàn)的Redux-Observable這樣的Redux中間件。

注意,我們這里的代碼中,并未使用dispatch action這樣的方式去嚴(yán)格模擬Redux。

再深入考慮,在比較復(fù)雜的場(chǎng)景下,reducer其實(shí)很復(fù)雜。比如說(shuō),視圖上發(fā)起一個(gè)操作,會(huì)需要修改視圖的好多地方,因此也就是要修改全局狀態(tài)樹(shù)的不同位置。

在這樣的場(chǎng)景中,從視圖發(fā)起的某個(gè)action,要么調(diào)用一個(gè)很復(fù)雜的reducer去到處改數(shù)據(jù),要么再次發(fā)起多個(gè)action,讓很多個(gè)reducer各自改自己的數(shù)據(jù)。

前者的問(wèn)題是,代碼耦合太嚴(yán)重;后者的問(wèn)題是,整個(gè)流程太難追蹤,比如說(shuō),某一塊狀態(tài),想要追蹤到自己是被從哪里發(fā)起的修改所改變的,是非常困難的事情。

如果我們能夠把Observable上面的同步修改過(guò)程視為reducer,就可以從另外一些角度大幅簡(jiǎn)化代碼,并且讓聯(lián)動(dòng)邏輯清晰化。例如,如果我們想描述一篇文章的編輯權(quán)限:

const editable$ = Observable.combineLatest(article$, me$)
.map(arr => {
let [article, me] = arr
return me.isAdmin || article.author === me.id
})

這段代碼的實(shí)質(zhì)是什么?其實(shí)本質(zhì)上還是reducer,表達(dá)的是數(shù)據(jù)的合并與轉(zhuǎn)換過(guò)程,而且是同步的。我們可以把a(bǔ)rticle和me的變更reduce到article$和me$里,由它們派發(fā)隱式的action去推動(dòng)editable計(jì)算新值。

更詳細(xì)探索的可以參見(jiàn)之前的這篇文章:復(fù)雜單頁(yè)應(yīng)用的數(shù)據(jù)層設(shè)計(jì)

小結(jié)

本篇通過(guò)一些簡(jiǎn)單例子介紹了RxJS的使用場(chǎng)景,可以用這么一句話來(lái)描述它:

其文簡(jiǎn),其意博,其理奧,其趣深

RxJS提供大量的操作符,用于處理不同的業(yè)務(wù)需求。對(duì)于同一個(gè)場(chǎng)景來(lái)說(shuō),可能實(shí)現(xiàn)方式會(huì)有很多種,需要在寫(xiě)代碼之前仔細(xì)斟酌。由于RxJS的抽象程度很高,所以,可以用很簡(jiǎn)短代碼表達(dá)很復(fù)雜的含義,這對(duì)開(kāi)發(fā)人員的要求也會(huì)比較高,需要有比較強(qiáng)的歸納能力。

本文是入職螞蟻金服之后,第一次內(nèi)部分享,科普為主,后面可能會(huì)逐步作一些深入的探討。

螞蟻的大部分業(yè)務(wù)系統(tǒng)前端不太適合用RxJS,大部分是中后臺(tái)CRUD系統(tǒng),因?yàn)閮蓚€(gè)原因:整體性、實(shí)時(shí)性的要求不高。

什么是整體性?這是一種系統(tǒng)設(shè)計(jì)的理念,系統(tǒng)中的很多業(yè)務(wù)模塊不是孤立的,比如說(shuō),從展示上,GUI與命令行的差異在于什么?在于數(shù)據(jù)的冗余展示。我們可以把同一份業(yè)務(wù)數(shù)據(jù)以不同形態(tài)展示在不同視圖上,甚至在PC端,由于屏幕大,可以允許同一份數(shù)據(jù)以不同形態(tài)同時(shí)展現(xiàn),這時(shí)候,為了整體協(xié)調(diào),對(duì)此數(shù)據(jù)的更新就會(huì)要產(chǎn)生很多分發(fā)和聯(lián)動(dòng)關(guān)系。

什么是實(shí)時(shí)性?這個(gè)其實(shí)有多個(gè)含義,一個(gè)比較重要的因素是服務(wù)端是否會(huì)主動(dòng)向推送一些業(yè)務(wù)更新信息,如果用得比較多,也會(huì)產(chǎn)生不少的分發(fā)關(guān)系。

在分發(fā)和聯(lián)動(dòng)關(guān)系多的時(shí)候,RxJS才能更加體現(xiàn)出它比Generator、Promise的優(yōu)勢(shì)。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 原生JS實(shí)現(xiàn)加載進(jìn)度條

    原生JS實(shí)現(xiàn)加載進(jìn)度條

    這篇文章主要為大家詳細(xì)介紹了原生JS實(shí)現(xiàn)加載進(jìn)度條,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • firefox下獲取下列框選中option的text的代碼

    firefox下獲取下列框選中option的text的代碼

    Firefox下面沒(méi)有innerText,所以我們想在firefox下獲取下列框選中option的text(注意不是value)時(shí)會(huì)比較吃力。筆者結(jié)合自己在項(xiàng)目中的解決方案和代碼總結(jié)一下,請(qǐng)大家指教。
    2010-06-06
  • js實(shí)現(xiàn)拖動(dòng)模態(tài)框

    js實(shí)現(xiàn)拖動(dòng)模態(tài)框

    這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)拖動(dòng)模態(tài)框,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • javascript天然的迭代器

    javascript天然的迭代器

    有一個(gè)數(shù)n=5,不用for循環(huán),怎么返回[1,2,3,4,5]這樣一個(gè)數(shù)組
    2010-10-10
  • 前端js中的事件循環(huán)eventloop機(jī)制詳解

    前端js中的事件循環(huán)eventloop機(jī)制詳解

    這篇文章主要給大家介紹了關(guān)于前端js中事件循環(huán)eventloop機(jī)制的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用js具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • javascript時(shí)間排序算法實(shí)現(xiàn)活動(dòng)秒殺倒計(jì)時(shí)效果

    javascript時(shí)間排序算法實(shí)現(xiàn)活動(dòng)秒殺倒計(jì)時(shí)效果

    這篇文章主要介紹了javascript時(shí)間排序算法實(shí)現(xiàn)活動(dòng)秒殺倒計(jì)時(shí)效果,即一個(gè)頁(yè)面多個(gè)倒計(jì)時(shí)排序,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-03-03
  • 不使用瀏覽器運(yùn)行javascript代碼的方法

    不使用瀏覽器運(yùn)行javascript代碼的方法

    用js寫(xiě)一段小程序,但是又覺(jué)得使用瀏覽器去運(yùn)行挺麻煩的,下面為大家介紹下如何使用java程序調(diào)用javascript程序,有類似需求的朋友可以參考下哈,希望對(duì)大家有所幫助
    2013-07-07
  • js彈出層包含flash 不能關(guān)閉隱藏的2種處理方法

    js彈出層包含flash 不能關(guān)閉隱藏的2種處理方法

    js彈出層包含flash 不能關(guān)閉隱藏的2種處理方法,需要的朋友可以參考一下
    2013-06-06
  • js tab效果代碼增強(qiáng)版

    js tab效果代碼增強(qiáng)版

    兼容IE,firefox的js tab效果代碼增強(qiáng)版
    2008-04-04
  • uni-app微信小程序下拉多選框?qū)嵗a

    uni-app微信小程序下拉多選框?qū)嵗a

    這篇文章主要給大家介紹了關(guān)于uni-app微信小程序下拉多選框的相關(guān)資料,在通過(guò)uniapp做app開(kāi)發(fā)的時(shí)候,有場(chǎng)景需要用到下拉選擇框,需要的朋友可以參考下
    2023-08-08

最新評(píng)論