學習RxJS: 匯入

來源:互聯網
上載者:User

標籤:ati   協助   iterator   java   有序   非同步呼叫   合并   擴充   amd   

引子

新手們在非同步編程裡跌倒時,永遠會有這麼一個經典問題:怎麼在一次非同步呼叫裡return一個結果啊?

老司機說要用回呼函數,然後有條件判斷的嵌套回調(回調地獄)問題來了;

老司機推薦用事件,然後非同步流程裡有順序依賴;

老司機推薦用Promise,然後有順序依賴的流程裡,居然還想訂閱事件;

老司機建議試試協程,誰知對方想要合并兩個非同步呼叫;

……

以上,是非同步編程裡要面對的一些難題,也是ReactiveX API 所致力解決的

是什麼

知道有 ReactiveX 這麼一回事, 源於一位巨硬鐵粉的安利示範:Reactive LINQ 加持的C#,簡潔且頗具表達力;隨後,便是萬眾矚目的 Angular 2,這貨的標配大禮包裡就有RxJS,比比皆是的 api.invocation.map(...).subscribe(fn, fn, fn) 片斷,讓jQuery青年們一頭霧水。

落伍總是不好的,林子裡的鳥都在討論FRP時,我們也要跟上:

ReactiveX是Reactive Extensions的縮寫,一般簡寫為Rx,最初是LINQ的一個擴充,由微軟的架構師Erik Meijer領導的團隊開發,在2012年11月開源,Rx是一個編程模型,目標是提供一致的編程介面,協助開發人員更方便的處理非同步資料流,Rx庫支援.NET、JavaScript和C++,Rx近幾年越來越流行了,現在已經支援幾乎全部的流行程式設計語言了,Rx的大部分語言庫由ReactiveX這個組織負責維護,比較流行的有RxJava/RxJS/Rx.NET,社區網站是 reactivex.io。

概念

ReactiveX 的自述是  “An API for asynchronous programming with observable streams”,那麼,什麼是Observable,什麼又是Stream呢?

Stream

Erik Meijer發過一篇paper: “Your Mouse Is a Database”,大概意思是說,使用者的滑鼠點擊其實是一個無窮而即時的事件序列,可以將其視為一個與時間軸相關的資料流,我們 可以查詢並操作這個資料流,在它可用時(或者等待資料流可用):

 在 Rx 編程中,任何資料都可以被表達為資料流的形式,我們要做的是,對資料流進行訂閱、查詢、過濾、打平、歸併等各種操作。

由於是對 資料流序列 進行訂閱(觀察),Rx 的編程模型實際是基於 Observer pattern 和 Iterator pattern 這兩種設計模式構建的。

Observable

在Rx中,Observable就是一個序列,它按序對訂閱者(subscriber)進行值的推送,遵循一套 “Don’t call us; we’ll call you.” 的基本法。

基於 Observable 的模式, 和傳統的 Observer pattern有兩點本質的不同:

  1. Observable 只在至少有一個訂閱者時,資料才開始流動
  2. 在資料流結束(iterator 不再hasNext)時,Observable會發出通知(onCompleted)
怎麼用

程式員們大都被調教成了馬基雅維利主義者:“整點有用的”。所以,還是來看看RxJS怎麼用吧:

情境

我有一個C類區域網路,想要挨個ping一下網路內的裝置,看看哪些IP線上(並不知道DHCP的用戶端列表,所以得從 xxx.xxx.xxx.2 ping到 xxx.xxx.xxx.254)

思路

很明顯,ping 是一個非同步操作,這裡大概有 254 – 2 = 252 個非同步作業,痛點不在於非同步,而在於流程式控制制,在RxJS 裡,可以很方便的把Observable源進行歸併(merge),從而讓非同步資料流可控且有序

RxJS方案依賴

 

     JavaScript 
12345 "dependencies": {    "ping": "^0.1.10",    "ramda": "^0.21.0",    "rx": "^4.1.0",}

 

代碼

 

     JavaScript 
12345678910111213141516171819202122232425262728293031 var Rx = require(‘rx‘)var R = require(‘ramda‘)var pingCommand = require(‘ping‘) var config = {  timeout: 10,       // 逾時為10秒  extra: ["-i 2"],   // 每次發包間隔時間長度}function promisablePing(host) {  return new Promise((resolve, reject) => {    pingCommand.sys.probe(host      , isAlive => isAlive ? resolve(host) : reject(`${host}: unreachable.`)      , config)  })}function ping(host) {  return Rx.Observable.create(observer => {    return promisablePing(host)      .then(host => observer.onNext(host))      .then(_ => observer.onCompleted())      .catch(err => observer.onError(err))  })} var tasks = R.range(2, 254).map(i => ping(`192.168.50.${i}`))Rx.Observable  .merge(...tasks)  .subscribe(    host => console.log(`pong: ${host}`),    err => console.error(err)  )

 

說明

代碼足夠簡單,值得說明的是:

  1. Rx.Observable.create會建立一個Observable對象,對它進行訂閱的觀察者即create函數中回調的入值observer,觀察者有三個方法:onNext, onCompleted, and onError:
    1. onNext :在序列推送一個新值時被調用,對應到觀察者的subscribe第一個函參
    2. onCompleted:序列中已無值可用,對應到觀察者的subscribe第三個函參
    3. onError:序列中發生了錯誤,對應到觀察者的subscribe第二個函參
  2. merge合并後的操作流,是一個對IP在:192.168.50.2 – 254 範圍內的裝置進行Ping的操作序列,但是Observable有一個特點,就是任何時候觸發了 錯誤回調(即Rx.Observable.create建立那個的觀察者,進行了onError通知,從而觸發了消費者提供給subscribe函數第二個參數)那麼整個Observable序列就此結束。比如,我的C類子網就兩台裝置線上:xxx.xxx.xxx..100 和 xxx.xxx.xxx.200,然後 xxx.xxx.xxx.2 在10秒後逾時報錯,那這條Observable時間軸看起來就是這樣的:
    BEGIN-> .100-.200---------------------[.2 error] ->END
  3. Ramda 是一個優秀的函數式JS庫,當然,用成了lodash也不壞
小結

以上,只是冰山一角,下回,想聊聊基於RxJS的Web架構:Cycle.js

學習RxJS: 匯入

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.