RxJS 系列故事(1)——理解響應式程式設計

橘子小睿發表於2020-03-12

在學習 RxJS 的過程中,我發現很多概念晦澀難懂,比如:響應式程式設計、觀察者模式、各種各樣的操作符以及多播等等。理解這些概念通常會花費大量時間,而且很難將它們吃透。於是我就寫了一個關於「大學生創業」的小故事,以幫助大家理解 RxJS 的核心概念。

故事的主角小王是一個計算機專業的大學生,接下來讓我們先跟隨小王的腳步,去理解指令式程式設計、宣告式程式設計以及響應式程式設計。

指令式程式設計

小王畢業之後就回老家開了一家超市。小王一個人忙不過來,於是就僱了李叔來店裡幫忙。為了更好地瞭解超市的經營狀況,小王就讓李叔去統計一下上週的總支出。可李叔哪會這個呀,於是小王只好交代清楚每一個步驟:

1、記錄每天的支出

2、將一週內每天的支出加起來

3、將結果發給老闆

在處理問題時,指令式程式設計需要通過程式語言的迴圈語句(for/while)或條件語句(switch/if)等,去描述清楚每一步要怎麼做(How),才能達到最終的結果(What)。

用命令式的方式,來計算總支出,程式碼如下:

function getTotalCosts(costs) {
  let total = 0;
  for (let i = 0; i < 7; i++) {
    total = total + costs[i];
  }
  return total;
}
複製程式碼

李叔按照小王的指令計算好了總支出。但小王得知後卻有點苦惱,因為支出的費用比較高。於是,就讓李叔趕緊再算一下:如果每天減少百分之十的支出,看看一週能省多少錢?可李叔還是不知道如何計算。小王心想,這不就和之前差不多嗎?沒辦法,還是隻有手把手教:

1、記錄每天的支出

2、將每天的支出乘以0.9

3、將一週內每天的支出加起來

4、將結果發給老闆

用命令式的方式,來計算減少後的總支出,程式碼如下:

function getReducedCosts(costs) {
  let total = 0;
  for (let i = 0; i < 7; i++) {
    total = total + costs[i] * 0.9;
  }
  return total;
}
複製程式碼

是不是感覺很重複?這就是指令式程式設計的一個問題。現實中的很多問題都具有「相似的模式」,如果將這些模式抽象出來,就可以減少大量重複程式碼。

宣告式程式設計

小王覺得只統計支出還不夠,也需要關注店裡的營業額。但店裡的事情太多了,手把手教李叔去做真的很累。於是,他便讓學財務的表妹過來幫忙。這樣小王只需告訴表妹:幫我統計一下今天店裡的營業額,即可。至於怎麼計算營業額,表妹自有辦法解決。

在處理問題時,宣告式程式設計只需描述要做什麼(What),而不需要告訴機器具體要怎麼做(How)。

用宣告式的方式,來計算之前的兩個問題,程式碼如下:

const getTotalCosts = (costs) => costs.reduce((res, item) => res + item);
const getReducedCosts = (costs) => costs.reduce((res, item) => res + item * 0.9);
複製程式碼

可以看到,程式碼簡潔了很多。在指令式程式設計中的迴圈語句,都被封裝到了 reduce 函式中。這讓開發效率有了提升。此外,宣告式程式設計也是函數語言程式設計的基礎。

響應式程式設計

雖然表妹的到來給小王減輕了不少負擔,但這樣的管理模式,對學計算機的他而言還是不夠智慧。於是,他就買了一個商家管理系統。只要賣出一件商品,系統就會自動計算營業額,這樣小王隨時想檢視報表都沒問題。因為報表會「響應」商品的變化。

響應式程式設計是一種面向「資料流」和「變化傳播」的程式設計正規化(來自維基百科)。有點難懂是不是? 不過我們可以這麼來理解:

資料流可以想象成在超市結賬時的發生的一系列事件,比如:

-------薯片x1------泡鳳爪x1------無糖可樂x3------餅乾x2------時間軸--->
複製程式碼

而變化傳播可以用收銀臺變化著的總價來理解:隨著收銀員描完一件件商品的二維碼,螢幕上顯示的總價格也在不斷髮生改變。

響應式程式設計與我們之前提到的指令式程式設計、宣告式程式設計有很大的不同。不管是指令式程式設計還是宣告式程式設計,描述的都是一個「瞬時」的過程。就好比讓表妹去計算一下目前的營業額,等表妹計算完之後,即便有新的商品賣出,這個數字也不會再發生變化,除非重新計算一次。

而響應式程式設計更多的是對關係的描述。比如:營業額 = 賣出商品的價格之和。只要有新的商品賣出,營業額就會隨之發生變化。

於我而言,響應式程式設計帶來的更多是思維方式上的轉變,也就是從「pull」到「push」模式的轉變。而「pull」和「push」都是從「資料消費者」的角度來描述的。比如我想獲取某個資料,那麼我就去呼叫某個函式,這是主動「pull」的過程。而當我訂閱一個資料來源之後,資料就會在合適的時機推送給我,這是「push」模式。

在響應式程式設計中,「預鋪設管道」非常重要,當我們將管道鋪設好之後,資料就會隨著管道流動,一切都會按照我們預設的邏輯發生。

小結

通過小王的創業故事,我們瞭解了指令式程式設計、宣告式程式設計和響應式程式設計。下面,讓我們再回顧一下它們的特點:

  1. 指令式程式設計:需要描述清楚每一步要怎麼做(How),才能達到最終的結果(What)。

  2. 宣告式程式設計:只需描述要做什麼(What),而不需要告訴機器具體要怎麼做(How)。

  3. 響應式程式設計:基於資料流和變化傳播。體現了響應變化的過程。

參考

zhuanlan.zhihu.com/p/34445114

相關文章