很多開發(fā)人員,不論是前端、后端還是移動端都會從各種途徑中獲知響應(yīng)式編程這個概念,因為很多框架都開始宣稱支持響應(yīng)式開發(fā)。在我們意識到這一點時,大家都會嘗試搜索各種文章資料想了解響應(yīng)式編程到底是什么,可是互聯(lián)網(wǎng)資料真的是太“豐富”了,豐富到你看了看了半天,可能還摸不清頭腦,因為響應(yīng)式理論是從問題的底層重建了整個概念體系,一個概念牽扯出另一個概念,然后概念越來越多,很容易把人繞暈。本文嘗試在表面梳理一下響應(yīng)式編程的脈絡(luò),力求清晰,供各位想深入研究的有所參考。
要理解響應(yīng)式編程的脈絡(luò),就需要將這個詞拆分成兩部分:響應(yīng)式 和 編程。
編程
編程指的是編程范式,計算機語言發(fā)展到今天,出現(xiàn)了很多編程范式(詳見維基百科),響應(yīng)式編程是最近幾年流行起來的。除了響應(yīng)式編程之外,我們常用的編程范式還有命令式編程和在命令式編程基礎(chǔ)上擴展的面向?qū)ο缶幊?/strong>以及函數(shù)式編程。
因此,總結(jié)一下,現(xiàn)在流行的編程范式:命令式、面向?qū)ο?、函?shù)式和響應(yīng)式。
響應(yīng)式
在命令式編程中,對于語句:a:=b+c,當(dāng)語句執(zhí)行時,a獲得了語句的執(zhí)行結(jié)果,此后,參數(shù)b和c的任何改變對a沒有影響。在響應(yīng)式編程中,對于語句:a:=b+c,當(dāng)參數(shù)b和c發(fā)生變化時,a會自動隨著變化,而不必重新執(zhí)行語句。
一些直觀的示例可以更好的理解“響應(yīng)”,如:Excel表格中,某個單元格產(chǎn)生變化時,其它單元格也會產(chǎn)生相應(yīng)的變化。APP從服務(wù)器接收到某條交易記錄時自動顯示在UI界面上。
響應(yīng)式作為一種設(shè)計思想在不同層面不同維度可以有不同的應(yīng)用。應(yīng)用到平常意義的數(shù)據(jù)流層面,就是Reactive Stream;如果應(yīng)用到服務(wù)流層面,就是響應(yīng)式微服務(wù);用在Web設(shè)計上就有了響應(yīng)式Web設(shè)計;用在架構(gòu)層面就是響應(yīng)式架構(gòu)。
響應(yīng)式編程
響應(yīng)式編程是一種面向數(shù)據(jù)流和變化傳播的異步編程范例,數(shù)據(jù)流可以是I/O,事件等。
通常,某種具體的編程語言都會傾向于特定的編程范式,如Fortran語言是命令式編程語言,Java在設(shè)計上更加支持面向?qū)ο缶幊?,Haskell是函數(shù)式編程語言,而Scala則同時支持函數(shù)式和面向?qū)ο缶幊?。響?yīng)式編程沒有特定的編程語言,其實現(xiàn)是建立在現(xiàn)有編程語言基礎(chǔ)之上的,因此就有:
具體實現(xiàn)
針對響應(yīng)式編程理論,當(dāng)前主流實現(xiàn)有兩類:一種是函數(shù)響應(yīng)式編程FPR,一種是具有函數(shù)風(fēng)格的響應(yīng)式實現(xiàn)——響應(yīng)式函數(shù)編程RFP(reactive-functional programming)。
注意,這是兩種不同的實現(xiàn),函數(shù)響應(yīng)式編程FRP是建立在函數(shù)編程之上的響應(yīng)式實現(xiàn);響應(yīng)式函數(shù)編程RFP是在命令式操作系統(tǒng)之上的一層抽象,借鑒了函數(shù)式編程風(fēng)格,用于處理異步和事件驅(qū)動場景,同時可以避免像計算機需要跨線程和網(wǎng)絡(luò)邊界處理復(fù)雜的狀態(tài)那樣思考問題。
函數(shù)響應(yīng)式編程FPR有基于Scala語言實現(xiàn)的Akka-Streams,響應(yīng)式函數(shù)編程RFP有ReactiveX和Reactor等。
ReactiveX
ReactiveX,即Reactive Extension,響應(yīng)式擴展Rx。
Eric于2007年夏天在Microsoft創(chuàng)建了Rx,2009年11月18日Rx.Net發(fā)布,并移植到Microsoft.Phone.Reactive for Windows Phone 7。Jafar Husain于2011年離開Microsoft加入Netflix,開始布道Rx并在Netflix的客戶端UI棧完整地實現(xiàn)了異步流式處理。然后,他開始推動負責(zé)Netflix中間層API的Ben Christensen使用Rx。Ben于2012年開始RxJava并在2013年將代碼遷移到Github。
隨著Rx在業(yè)界越來越受歡迎,Eric于2012年離開Microsoft并創(chuàng)建了Applied Duality公司,將所有精力投入到構(gòu)建標準化的跨語言,跨平臺的異步實時數(shù)據(jù)流式處理API,即ReactiveX.io。
當(dāng)前,Rx包括RxJava,RxJS,Rx.Net,RxScala,RxClojure,RxSwift等18種語言實現(xiàn)。
Reactor
Reactor項目是Spring基于Reactive Streams規(guī)范(由4個簡單的Java接口:Publisher,Subscriber,Subscription 和 Processor,一個文本規(guī)范和一個TCK組成)提供的響應(yīng)式實現(xiàn),目的是為了讓Spring生態(tài)體系能夠支持業(yè)界越來越火的響應(yīng)式開發(fā)。
Spring并未直接引入類似RxJava來作為其框架的一部分,而是選擇另造輪子。從Spring 5開始,開發(fā)人員就可以有Spring Web Reactive和Spring Web MVC兩種選擇。
當(dāng)前,Reactor項目包含Reactor Core,Reactor Test,Reactor Adapter,Reactor Netty,Reactor Extra,Reactor Kafka,Reactor Core .NET 和 Reactor Core JS。
Rx的特點
本節(jié)摘自《ReactiveX/RxJava文檔中文版》
Rx從同步集合的Iterable/Iterator反向演化而來,是一個使用可觀察數(shù)據(jù)流進行異步編程的編程接口,ReactiveX結(jié)合了觀察者模式、迭代器模式和函數(shù)式編程的精華。
使用觀察者模式
簡化代碼
使用Observable的優(yōu)勢
Rx擴展了觀察者模式用于支持數(shù)據(jù)和事件序列,添加了一些操作符,它讓你可以聲明式的組合這些序列,而無需關(guān)注底層的實現(xiàn):如線程、同步、線程安全、并發(fā)數(shù)據(jù)結(jié)構(gòu)和非阻塞IO。
在Rx中,一個觀察者(Observer)訂閱一個可觀察對象(Observable)。觀察者對Observable推送的數(shù)據(jù)或數(shù)據(jù)序列作出響應(yīng)。這種模式可以極大地簡化并發(fā)操作,因為它創(chuàng)建了一個處于待命狀態(tài)的觀察者哨兵,在未來某個時刻響應(yīng)Observable的通知,不需要阻塞等待Observable推送數(shù)據(jù)。
概念與術(shù)語
直譯為反應(yīng)性的,有活性的,根據(jù)上下文一般翻譯為反應(yīng)式、響應(yīng)式
可迭代對象,支持以迭代器的形式遍歷,許多語言中都存在這個概念
可觀察對象,在Rx中定義為更強大的Iterable,在觀察者模式中是被觀察的對象,一旦數(shù)據(jù)產(chǎn)生或發(fā)生變化,會通過某種方式通知觀察者或訂閱者
觀察者對象,監(jiān)聽Observable推送的數(shù)據(jù)并做出響應(yīng),Subscriber是它的一個特殊實現(xiàn)
(摘自Scala官方文檔)
所謂Future,是一種用于指代某個尚未就緒的值的對象。而這個值,往往是某個計算過程的結(jié)果:若該計算過程尚未完成,我們就說該Future未就位;若該計算過程正常結(jié)束,或中途拋出異常,我們就說該Future已就位。
Future的就位分為兩種情況:當(dāng)Future帶著某個值就位時,我們就說該Future攜帶計算結(jié)果成功就位。當(dāng)Future因?qū)?yīng)計算過程拋出異常而就緒,我們就說這個Future因該異常而失敗。
Future的一個重要屬性在于它只能被賦值一次。一旦給定了某個值或某個異常,future對象就變成了不可變對象——無法再被改寫。
(摘自Scala官方文檔)
如果說futures是為了一個還沒有存在的結(jié)果,而當(dāng)成一種只讀占位符的對象類型去創(chuàng)建,那么promise就被認為是一個可寫的,可以實現(xiàn)一個future的單一賦值容器。這就是說,promise通過這種success方法可以成功去實現(xiàn)一個帶有值的future。相反的,因為一個失敗的promise通過failure方法就會實現(xiàn)一個帶有異常的future。
當(dāng)我們使用迭代遍歷一個集合時,我們是從集合中拉?。≒ull)數(shù)據(jù)的。當(dāng)我們在集合或數(shù)據(jù)流上使用觀察者模式時,數(shù)據(jù)是推送給觀察者的。
在Rx中,可觀察對象Observable同時支持同步和異步實現(xiàn)。
在Rx中,可觀察對象Observable是有惰性的,只有被訂閱時,它才推送變化。這不同于eager類型如Future。
在Rx中,一個可觀察對象Observable流既不支持并發(fā)也不支持并行。不過,在一組異步的可觀察對象Observable流集合可以執(zhí)行并發(fā)和并行處理操作。
結(jié)論
本文粗略梳理了響應(yīng)式編程的概念體系,深入研究和實踐還需要沿著這條脈絡(luò)進行深層次的挖掘。不當(dāng)之處請回復(fù)指正。