什么是相應式編程。簡單的來說就是基于事件流的編程方式。
什么是事件流,事件流就是將要發(fā)生事件按照時間順序排序發(fā)生形成的。
舉個例子,比如我去星巴克點咖啡(注意我這里只強調(diào)我干了什么,這樣表述會比較容易理解),我點了杯咖啡,我支付了現(xiàn)金,我等待咖啡煮好,我拿到了咖啡,我喝咖啡,我離開星巴克,結束所有流;又或者我拿咖啡的時候出現(xiàn)錯誤,發(fā)現(xiàn)咖啡不是我的,這樣就會出錯了,這樣又結束了所有的流??梢詤⒖枷聢D,圓點代表每個事件,紅色叉代表錯誤,黑色豎條代表結束。

從例子和圖中你可以看到組成響應式編程的三種動作(數(shù)據(jù)):事件(數(shù)據(jù)),錯誤,結束。通過得到這三個響應式動作,我們就可以在程序中作出不同的相應,使得我們編寫的代碼更加高效,簡潔。
響應式編程構建基礎
發(fā)布者(事件發(fā)送方,可以向它訂閱)
訂閱者(事件訂閱方)
訂閱(將發(fā)布者和訂閱者聯(lián)系起來,使訂閱者可以向發(fā)布者發(fā)送數(shù)據(jù))

下面舉了個例子將使用觀察者模式來編寫一個簡單的功能。頁面上有一個按鈕和一個Label;當點擊按鈕,Label就會自動加1。HelloButtonController是監(jiān)聽者,HelloVM是發(fā)布者。HelloButtonController使用initCountOberver注冊對HelloVM的監(jiān)聽。HelloButtonController在onClickedBtnCallback接收到按鈕事件后,就調(diào)用HelloVM的addCount方法,HelloVM在更新了count的值后再掉用subjustCount通知HelloButtonController,讓它刷新Label的顯示。

相應式編程的開發(fā)庫
要實現(xiàn)響應式編程,就有需要有適合這種工具,市面上主流的開源庫RX系列,React,Agera等。
這里我們著重介紹RX庫,它有什么特點呢?
1、只提供響應式編程的訂閱功能;
2、提供豐富的處理響應式流的API;
3、支持多種語言平臺(java,c++,js,lua等)
使用rx的寫上面的例子的代碼:

使用KVO的實現(xiàn)同樣的例子

如此看來,代碼變得更加簡潔更加高效。
響應式編程的特點:
事件驅動:Event-driven
基于異步通信的應用程序實現(xiàn)了松耦合的設計,好過于純粹基于同步的方法調(diào)用。發(fā)送方和接受方可以實現(xiàn)調(diào)用,不要關心事件是如何傳播的細節(jié),通過接口實現(xiàn)通信。這就易于延伸,發(fā)展和維護,帶來更多的靈活性,并降低了維護成本。
由于異步通信的接受人可以在事件發(fā)生時或收到一條消息之前保持休眠狀態(tài),事件驅動event-driven的方法可以有效地利用現(xiàn)有資源,讓多個收件人可以共享一個硬件線程。相比基于同步的傳統(tǒng)應用程序,一個非阻塞的應用程序在重負載下可以擁有更低的延遲和更高的吞吐量,這將導致更低的運營成本,提高了資源利用率以及良好的終端用戶體驗。
在一個事件驅動的應用程序中,組件彼此交互是通過離散事件的生產(chǎn)者和消費者( production/consumption )。這些事件是以異步和非阻塞的方式發(fā)送和接收的。事件驅動的系統(tǒng)往往依靠推而不是拉或投票表決,即他們是在有消息時才推送數(shù)據(jù)給消費者,而不是通過一種浪費資源方式:讓消費者不斷地輪詢或等待數(shù)據(jù)。
異步發(fā)送事件:也被稱為消息傳遞意味著應用程序設計于高并發(fā),能夠無需改動利用多核硬件。任何一個CPU內(nèi)核都是能夠處理任何消息事件,這導致并行的機會急劇增加。
非阻塞:意味著應用程序在故障等突發(fā)情況下任何時候都能實現(xiàn)響應。而對于這一切所需的資源響應,例如CPU,內(nèi)存和網(wǎng)絡都不會發(fā)生壟斷。因此,它可以同時兼具更低的延遲,更高的吞吐量和更好的可擴展性。
傳統(tǒng)的服務器端架構是依賴于在一個單獨的線程中共享可變狀態(tài)和實現(xiàn)阻塞操作。這樣的系統(tǒng)在滿足不斷變化的需求時難以擴展伸縮,共享可變狀態(tài)需要同步,它引入了附帶的復雜性和不確定性,使得程序代碼很難理解和維護。把一個線程通過阻斷方式使用實際是限制了資源,并帶來高昂的喚醒成本。
事件的產(chǎn)生和處理的解耦,能夠讓運行平臺更關注同步細節(jié)以及事件是如何跨線程分發(fā)的,當程序抽象抬升到業(yè)務流程級別,你考慮的是事件如何傳播以及如何通過系統(tǒng)組件之間進行交互,而不是擺弄周圍的低級初始設備如線程和鎖。
事件驅動的系統(tǒng)使組件和子系統(tǒng)之間的松耦合。這是可擴展性和彈性的先決條件之一。通過消除復雜和強大的組件之間的依賴,事件驅動的應用可以通過影響最小的方式擴展現(xiàn)有的應用程序。
Resilient彈性
彈性有以下含義:
物質或物體擁有形狀上彈回的能力。
從困難中恢復的能力。
在一個reactive應用中,應變能力不是一個可有可無的東西,而是從一開始就成為設計的一部分。故障應對在編程模型中構建時就第一面對,這就導致應用程序是高度寬容失敗并在運行時能夠提供手段愈合修復自己。傳統(tǒng)的故障處理是不能做到這一點,因為它是要么防御小,要么過于激進,你必須在系統(tǒng)的一個個地方去處理異常Exception(banq:將你的方法到處加上try{}catch)。
為了管理失敗,我們需要一種方法來隔離它,使它不會擴散到其他健康的部位,并能觀察它,從失敗的上下文以外的安全點對其進行管理。如果其中一個出現(xiàn)故障,不影響其他的。這可以防止級聯(lián)故障的經(jīng)典的問題,并允許隔離管理問題。
事件驅動的松散耦合提供了組件在失敗下可以抓獲完全隔離的上下文場景,作為消息封裝,發(fā)送到其他組件時,在具體編程時可以檢查錯誤比如是否接受到,接受的命令是否可執(zhí)行等等,并決定如何應對。
這種方法創(chuàng)建了一個能讓業(yè)務邏輯保持清潔的系統(tǒng),顯式的隔離分開處理Exception的有利于觀察,管理和配置,并能讓系統(tǒng)自行愈合,并自動恢復。這類似在一個大公司內(nèi),將一個問題逐步向上升級,直到達到有權力來處理它的水平。
這個模型的美妙之處在于它是純粹的事件驅動,它是reactive組件和異步事件,意味著在分布式環(huán)境中具有在本地一臺服務器范圍內(nèi)相同的語義。
Responsive實時響應
這是迅速回應或作出適當?shù)姆磻囊馑迹?我們使用這個詞在一般意義上不應該與響應的網(wǎng)頁設計混淆,后者主要是指CSS媒體查詢和漸進增強。
響應的應用程序是實時的,耐看的,豐富的和協(xié)作。企業(yè)與他們的客戶建立一個開放的和持續(xù)的對話,歡迎他們通過響應的互動體驗。這使得它們更有效率,建立連接,并配備解決問題和完成任務的感覺。一個例子是,在使用谷歌Docs 時,幾個用戶能夠編輯文檔協(xié)作,能實時地讓他們看到彼此的編輯和注釋的結果。
對事件作出響應的應用程序,需要及時去做(just do it),即使存在故障情況。如果應用程序在長時間不做出回應,稱為延遲,這個系統(tǒng)實際是不可用的,因此不能被視為彈性。
當然并非所有應用如武器或醫(yī)療監(jiān)控系統(tǒng)這樣對實時要求如此高,但是通常他們在運行一段時間后出現(xiàn)迅速下降的性能,才可以從他們偏離了一點響應限制看出(banq: windows越用越慢),假如是金融交易應用程序可能會失去目前的交易沒有及時回應。
后壓(back pressure)
Reactive流的主要特征是“back pressure后壓”:也就是說,系統(tǒng)會在它的請求buffer被充滿時,將其推送會給發(fā)送者,讓發(fā)送者稍后再試,或者使用其他接收器,這就能確保發(fā)送者和接收者之間的管道不會被充滿,這樣才有機會獲得一個響應式系統(tǒng)。