最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺談Rx響應(yīng)式編程

 更新時(shí)間:2021年06月18日 11:16:12   作者:vivo互聯(lián)網(wǎng)技術(shù)  
在學(xué)習(xí)Rx編程的過(guò)程中,理解Observable這個(gè)概念至關(guān)重要,常規(guī)學(xué)習(xí)過(guò)程中,通常需要進(jìn)行多次碰壁才能逐漸開悟。這個(gè)有點(diǎn)像小時(shí)候?qū)W騎自行車,必須摔幾次才能掌握一樣。當(dāng)然如果有辦法能言傳,則可以少走一些彎路,盡快領(lǐng)悟Rx的精妙

一、Observable

Observable從字面翻譯來(lái)說(shuō)叫做“可觀察者”,換言之就是某種“數(shù)據(jù)源”或者“事件源”,這種數(shù)據(jù)源具有可被觀察的能力,這個(gè)和你主動(dòng)去撈數(shù)據(jù)有本質(zhì)區(qū)別。用一個(gè)形象的比喻就是Observable好比是水龍頭,你可以去打開水龍頭——訂閱Observable,然后水——數(shù)據(jù)就會(huì)源源不斷流出。這就是響應(yīng)式編程的核心思想——變主動(dòng)為被動(dòng)。不過(guò)這個(gè)不在本篇文章中詳解。

Observable是一種概念,可以通過(guò)不同的方式去具體實(shí)現(xiàn),本文通過(guò)高階函數(shù)來(lái)實(shí)現(xiàn)兩個(gè)常用Observable:fromEvent和Interval。通過(guò)講解對(duì)Observable的訂閱和取消訂閱兩個(gè)行為來(lái)幫助讀者真正理解Observable是什么。

二、高階函數(shù)

高階函數(shù)的概念來(lái)源于函數(shù)式編程,簡(jiǎn)單的定義就是一個(gè)函數(shù)的入?yún)⒒蛘叻祷刂凳且粋€(gè)函數(shù)的函數(shù)。例如:

function foo(arg){
    return function(){
        console.log(arg)
    }
}
const bar = foo(“hello world”)
bar()  // hello world

ps:高階函數(shù)能做的事情很多,這里僅僅針對(duì)本文需要的情形進(jìn)行使用。

上面這個(gè)foo函數(shù)的調(diào)用并不會(huì)直接打印hello world,而只是把這個(gè)hello world給緩存起來(lái)。后面我們根據(jù)實(shí)際需要調(diào)用返回出來(lái)的bar函數(shù),然后真正去執(zhí)行打印hello world的工作。

為啥要做這么一步封裝呢?實(shí)際上這么做的效果就是“延遲”了調(diào)用。而一切的精髓就在這個(gè)“延遲”兩個(gè)字里面。我們實(shí)際上是對(duì)一種行為進(jìn)行了包裝,看上去就像某種一致的東西,好比是快遞盒子。

里面可以裝不同的東西,但對(duì)于物流來(lái)說(shuō)就是統(tǒng)一的東西。因此,就可以形成對(duì)快遞盒的統(tǒng)一操作,比如堆疊、運(yùn)輸、存儲(chǔ)、甚至是打開盒子這個(gè)動(dòng)作也是一致的。

回到前面的例子,調(diào)用foo函數(shù),相當(dāng)于打包了一個(gè)快遞盒,這個(gè)快遞盒里面有一個(gè)固定的程序,就是當(dāng)打開這個(gè)快遞盒(調(diào)用bar)時(shí)執(zhí)行一個(gè)打印操作。

我們可以有foo1、foo2、foo3……里面有各種各樣的程序,但是這些foos,都有一個(gè)共同的操作就是“打開”。(前提是這個(gè)foo會(huì)返回一個(gè)函數(shù),這樣才能滿足“打開”的操作,即調(diào)用返回的函數(shù))。

function foo1(arg){
    return function(){
       console.log(arg+"?")
    }
}
function foo2(arg){
      return function(){
         console.log(arg+"!")
     }
}
const bar1 = foo1(“hello world”)
const bar2 = foo2("yes")
bar1()+bar2() // hello world? yes!

三、快遞盒模型

3.1、快遞盒模型1:fromEvent

有了上面的基礎(chǔ),下面我們就來(lái)看一下Rx編程中最常用的一個(gè)Observable—fromEvent(……)。對(duì)于Rx編程的初學(xué)者,起初很難理解fromEvent(……)和addEventListener(……)有什么區(qū)別。

btn.addEventListener("click",callback)
rx.fromEvent(btn,"click").subscribe(callback)

如果直接執(zhí)行這個(gè)代碼,確實(shí)效果是一樣的。那么區(qū)別在哪兒呢?最直接的區(qū)別是,subscribe函數(shù)作用在fromEvent(……)上而不是btn上,而addEventListener是直接作用在btn上的。subscribe函數(shù)是某種“打開”操作,而fromEvent(……)則是某種快遞盒。

fromEvent實(shí)際上是對(duì)addEventListener的“延遲”調(diào)用

function fromEvent(target,evtName){
    return function(callback){
        target.addEventListener(evtName,callback)
    }
}
const ob = fromEvent(btn,"click")
ob(console.log)// 相當(dāng)于 subscribe

哦!fromEvent本質(zhì)上是高階函數(shù)

至于如何實(shí)現(xiàn)subscribe來(lái)完成“打開”操作,不在本文討論范圍,在Rx編程中,這個(gè)subscribe的動(dòng)作叫做“訂閱”。“訂閱”就是所有Observable的統(tǒng)一具備的操作。再次強(qiáng)調(diào):本文中對(duì)Observable的“調(diào)用”在邏輯上相當(dāng)于subscribe。

下面再舉一個(gè)例子,基本可以讓讀者舉二反N了。

3.2、快遞盒模型2:interval

Rx中有一個(gè)interval,它和setInterval有什么區(qū)別呢?

估計(jì)有人已經(jīng)開始搶答了,interval就是對(duì)setInterval的延遲調(diào)用!bingo!

function interval(period){
    let i = 0
    return function(callback){
        setInterval(period,()=>callback(i++))
    }
}
const ob = interval(1000)
ob(console.log)// 相當(dāng)于 subscribe

從上面兩個(gè)例子來(lái)看,無(wú)論是fromEvent(……)還是Interval(……),雖然內(nèi)部是完全不同的邏輯,但是他們同屬于“快遞盒”這種東西,我們把它稱之為Observable——可觀察者。

fromEvent和Interval本身只是制作“快遞盒”的模型,只有調(diào)用后返回的東西才是“快遞盒”,即fromEvent(btn,"click")、interval(1000) 等等...

四、高階快遞盒

有了上面的基礎(chǔ),下面開始進(jìn)階:我們擁有了那么多快遞盒,那么就可以對(duì)這些快遞盒再封裝。

在文章開頭說(shuō)了,快遞盒統(tǒng)一了一些操作,所以我們可以把許許多多的快遞盒堆疊在一起,即組合成一個(gè)大的快遞盒!這個(gè)大的快遞盒和小的快遞盒一樣,具有“打開”操作(即訂閱)。當(dāng)我們打開這個(gè)大的快遞盒的時(shí)候,會(huì)發(fā)生什么呢?

可以有很多種不同的可能性,比如可以逐個(gè)打開小的快遞盒(concat),或者一次性打開所有小的快遞盒(merge),也可以只打開那個(gè)最容易打開的快遞盒(race)。

下面是一個(gè)簡(jiǎn)化版的merge方法:

function merge(...obs){
    return function(callback){
        obs.forEach(ob=>ob(callback)) // 打開所有快遞盒
    }
}

我們還是拿之前的fromEvent和interval來(lái)舉例吧!

使用merge方法對(duì)兩個(gè)Observable進(jìn)行組合:

const ob1 = fromEvent(btn,'click') // 制作快遞盒1
const ob2 = interval(1000) // 制作快遞盒2
const ob = merge(ob1,ob2) //制作大快遞盒
ob(console.log) // 打開大快遞盒

當(dāng)我們“打開”(訂閱)這個(gè)大快遞盒ob的時(shí)候,其中兩個(gè)小快遞盒也會(huì)被“打開”(訂閱),任意一個(gè)小快遞盒里面的邏輯都會(huì)被執(zhí)行,我們就合并(merge)了兩個(gè)Observable,變成了一個(gè)。

這就是我們?yōu)槭裁匆列量嗫喟迅鞣N異步函數(shù)封裝成快遞盒(Observable)的原因了——方便對(duì)他們進(jìn)行統(tǒng)一操作!當(dāng)然僅僅只是“打開”(訂閱)這個(gè)操作只是最初級(jí)的功能,下面開始進(jìn)階。

五、銷毀快遞盒

5.1、銷毀快遞盒——取消訂閱

我們還是以fromEvent為例子,之前我們寫了一個(gè)簡(jiǎn)單的高階函數(shù),作為對(duì)addEventListener的封裝:

function fromEvent(target,evtName){
    return function(callback){
        target.addEventListener(evtName,callback)
    }
}

當(dāng)我們調(diào)用這個(gè)函數(shù)的時(shí)候,就生成了一個(gè)快遞盒(fromEvent(btn,'click'))。當(dāng)我們調(diào)用了這個(gè)函數(shù)返回的函數(shù)的時(shí)候,就是打開了快遞盒(fromEvent(btn,'click')(console.log))。

那么我們?cè)趺慈ヤN毀這個(gè)打開的快遞盒呢?

首先我們需要得到一個(gè)已經(jīng)打開的快遞盒,上面的函數(shù)調(diào)用結(jié)果是void,我們無(wú)法做任何操作,所以我們需要構(gòu)造出一個(gè)打開狀態(tài)的快遞盒。還是使用高階函數(shù)的思想:在返回的函數(shù)里面再返回一個(gè)函數(shù),用于銷毀操作。

function fromEvent(target,evtName){
    return function(callback){
        target.addEventListener(evtName,callback)
        return function(){
            target.removeEventListener(evtName,callback)
        }
    }
}
const ob = fromEvent(btn,'click') // 制作快遞盒
const sub = ob(console.log) // 打開快遞盒,并得到一個(gè)可用于銷毀的函數(shù)
sub() // 銷毀快遞盒

同理,對(duì)于interval,我們也可以如法炮制:

function interval(period){
    let i = 0
    return function(callback){
        let id = setInterval(period,()=>callback(i++))
        return function(){
            clearInterval(id)
        }
    }
}
const ob = interval(1000) // 制作快遞盒
const sub = ob(console.log) // 打開快遞盒
sub() // 銷毀快遞盒

5.2、銷毀高階快遞盒

我們以merge為例:

function merge(...obs){
    return function(callback){
        const subs = obs.map(ob=>ob(callback)) // 訂閱所有并收集所有的銷毀函數(shù)
        return function(){
            subs.forEach(sub=>sub()) // 遍歷銷毀函數(shù)并執(zhí)行
        }
    }
}
 
const ob1 = fromEvent(btn,'click') // 制作快遞盒1
const ob2 = interval(1000) // 制作快遞盒2
const ob = merge(ob1,ob2) //制作大快遞盒
const sub = ob(console.log) // 打開大快遞盒
sub() // 銷毀大快遞盒

當(dāng)我們銷毀大快遞盒的時(shí)候,就會(huì)把里面所有的小快遞盒一起銷毀。

六、補(bǔ)充

到這里我們已經(jīng)將Observable的兩個(gè)重要操作(訂閱、取消訂閱)講完了,值得注意的是,取消訂閱這個(gè)行為并非是作用于Observable上,而是作用于已經(jīng)“打開”的快遞盒(訂閱Observable后返回的東西)之上!

Observable除此以外,還有兩個(gè)重要操作,即發(fā)出事件、完成/異常,(這兩個(gè)操作屬于是由Observable主動(dòng)發(fā)起的回調(diào),和操作的方向是相反的,所以其實(shí)不能稱之為操作)。

這個(gè)兩個(gè)行為用快遞盒就不那么形象了,我們可以將Observable比做是水龍頭,原先的打開快遞盒變成擰開水龍頭,而我們傳入的回調(diào)函數(shù)就可以比喻成接水的水杯!由于大家對(duì)回調(diào)函數(shù)已經(jīng)非常熟悉了,所以本文就不再贅述了。

七、后記

總結(jié)一下我們學(xué)習(xí)的內(nèi)容,我們通過(guò)高階函數(shù)將一些操作進(jìn)行了“延遲”,并賦予了統(tǒng)一的行為,比如“訂閱”就是延遲執(zhí)行了異步函數(shù),“取消訂閱”就是在上面的基礎(chǔ)上再“延遲”執(zhí)行了銷毀資源的函數(shù)。

這些所謂的“延遲”執(zhí)行就是Rx編程中幕后最難理解,也是最核心的部分。Rx的本質(zhì)就是將異步函數(shù)封裝起來(lái),然后抽象成四大行為:訂閱、取消訂閱、發(fā)出事件、完成/異常。

實(shí)際實(shí)現(xiàn)Rx庫(kù)的方法有很多,本文只是利用了高階函數(shù)的思想來(lái)幫助大家理解Observable的本質(zhì),在官方實(shí)現(xiàn)的版本中,Observable這個(gè)快遞盒并非是高階函數(shù),而是一個(gè)對(duì)象,但本質(zhì)上是一樣的

以上就是淺談Rx響應(yīng)式編程的詳細(xì)內(nèi)容,更多關(guān)于Rx響應(yīng)式編程的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 如何利用JavaScript?實(shí)現(xiàn)繼承

    如何利用JavaScript?實(shí)現(xiàn)繼承

    這篇文章主要介紹了如何利用JavaScript?實(shí)現(xiàn)繼承,JavaScript?在編程語(yǔ)言界是個(gè)特殊種類,它和其他編程語(yǔ)言很不一樣,JavaScript可以在運(yùn)行的時(shí)候動(dòng)態(tài)地改變某個(gè)變量的類型,下面小編將繼續(xù)介紹JavaScript如何實(shí)現(xiàn)繼承,需要的朋友可以參考下
    2022-02-02
  • 詳解開源的JavaScript插件化框架MinimaJS

    詳解開源的JavaScript插件化框架MinimaJS

    這篇文章主要介紹了開源的JavaScript插件化框架MinimaJS的詳解,詳細(xì)的介紹了MinimaJS的使用,具有一定的參考價(jià)值,有興趣的可以了解一下
    2017-10-10
  • js實(shí)現(xiàn)仿網(wǎng)易點(diǎn)擊彈出提示同時(shí)背景變暗效果

    js實(shí)現(xiàn)仿網(wǎng)易點(diǎn)擊彈出提示同時(shí)背景變暗效果

    這篇文章主要介紹了js實(shí)現(xiàn)仿網(wǎng)易點(diǎn)擊彈出提示同時(shí)背景變暗效果,涉及javascript彈出框及頁(yè)面元素樣式操作的相關(guān)技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2015-08-08
  • DIV菜單層實(shí)現(xiàn)代碼

    DIV菜單層實(shí)現(xiàn)代碼

    昨天我問(wèn)一美工jQuery怎么樣了,他說(shuō)簡(jiǎn)單的還可以,復(fù)雜的就不行了,我又問(wèn)是哪種程度的復(fù)雜?
    2010-11-11
  • 原生js獲取元素樣式的簡(jiǎn)單方法

    原生js獲取元素樣式的簡(jiǎn)單方法

    下面小編就為大家?guī)?lái)一篇原生js獲取元素樣式的簡(jiǎn)單方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-08-08
  • 微信小程序?qū)崿F(xiàn)頁(yè)面分享onShareAppMessage

    微信小程序?qū)崿F(xiàn)頁(yè)面分享onShareAppMessage

    這篇文章主要介紹了微信小程序?qū)崿F(xiàn)頁(yè)面分享onShareAppMessage,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • JS中with的替代方法與String中的正則方法詳解

    JS中with的替代方法與String中的正則方法詳解

    最近這幾天在升級(jí)自己的MVVM 框架,遇到很多小問(wèn)題,所以想著就在這里統(tǒng)一解決了。文中主要介紹了關(guān)于Javascript中with的替代方法與String中的正則方法,有需要的朋友們可以參考借鑒,下面來(lái)一起看看吧。
    2016-12-12
  • Javascript - HTML的request類

    Javascript - HTML的request類

    Javascript - HTML的request類...
    2006-07-07
  • 關(guān)于ckeditor在bootstrap中modal中彈框無(wú)法輸入的解決方法

    關(guān)于ckeditor在bootstrap中modal中彈框無(wú)法輸入的解決方法

    今天小編就為大家分享一篇關(guān)于ckeditor在bootstrap中modal中彈框無(wú)法輸入的解決方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-09-09
  • 談?wù)勎覍?duì)JavaScript中typeof和instanceof的深入理解

    談?wù)勎覍?duì)JavaScript中typeof和instanceof的深入理解

    這次主要說(shuō)說(shuō)javascript的類型判斷函數(shù)typeof和判斷構(gòu)造函數(shù)原型instanceof的用法和注意的地方,對(duì)本文感興趣的朋友一起看看吧
    2015-12-12

最新評(píng)論

永胜县| 宜宾市| 宁蒗| 库伦旗| 南丰县| 乌海市| 高清| 呼图壁县| 塘沽区| 贵州省| 铅山县| 张家川| 兴文县| 绥化市| 法库县| 乐山市| 河津市| 宁津县| 宽城| 长丰县| 天柱县| 东乌珠穆沁旗| 车致| 潍坊市| 称多县| 灌南县| 卢氏县| 秦安县| 马边| 普兰店市| 灌阳县| 武鸣县| 潮安县| 北碚区| 花垣县| 佛山市| 囊谦县| 吉隆县| 德钦县| 庆城县| 临夏县|