揚(yáng)帆起航:從命令式編程到函數(shù)響應(yīng)式編程

前言:在大學(xué)時(shí)期,我用Ionic寫過一個(gè)查看校園信息的app,利用投放廣告盈利的方式,我賺到了一臺(tái)MacBook Pro。在之后的日子里,無論是工作,學(xué)習(xí)還是生活,它都給我?guī)順O大的便捷。我至今仍心存感激。所以我對(duì)Ionic的核心框架Angular充滿好感。即使現(xiàn)在的工作中用react居多,但是閑暇時(shí)還是會(huì)追一追Angular的文檔,寫一寫筆記。
隨著工作經(jīng)驗(yàn)愈發(fā)豐富,Angular越來越演變成一種信仰。我在業(yè)務(wù)編碼過程中遇到的諸多問題在Angular中均有優(yōu)雅的解決方案,這點(diǎn)足令我震撼。所以我決定將它分為不同的章節(jié),依次研讀。
我首先選擇了Rx,因?yàn)樗粌H是Angular的核心之一,而且我覺得學(xué)習(xí)完之后可以應(yīng)用到現(xiàn)在的工作中,兩者兼得。幸運(yùn)的是,我在西湖邊發(fā)現(xiàn)了修煉的寶地:平湖秋月。看著蕩漾的水波,想象自己是一段流,似乎就化身為Observable,與Rx心靈相通。這極大的提高了我修煉的速度。下面的章節(jié)我會(huì)將自己學(xué)到的知識(shí)記錄下來,與各位分享。

平湖秋月邊修煉Rx

首先,我認(rèn)為前端開發(fā)做好2件事情就夠了:1.渲染界面,2.根據(jù)用戶輸入渲染界面。其中渲染界面可以利用React之類的庫來完成,它們提供了一種從state映射到view的方式,你只需要管理好state即可,渲染view的工作丟給它們?nèi)ネ瓿?。而根?jù)用戶輸入渲染界面這部分會(huì)比較復(fù)雜,其中涉及到異步處理,業(yè)務(wù)邏輯代碼編寫等等。項(xiàng)目變得有一定規(guī)模之后,會(huì)變得比較難以維護(hù)。一個(gè)很重要的原因在于沒有一個(gè)直觀的組織代碼的方式,讓維護(hù)者一眼看上去就知道這段代碼想要表達(dá)什么。

接下來,要想解決這個(gè)問題,需要好好審視一下web開發(fā)的本質(zhì)。用戶點(diǎn)擊鼠標(biāo),觸發(fā)了一個(gè)事件,你的程序接收到之后開始做一些處理。用戶移動(dòng)鼠標(biāo),觸發(fā)了一個(gè)事件,你的程序接收到之后開始做一些處理。只要稍微一想,就會(huì)明白web開發(fā)其實(shí)就是和一系列的事件打交道,只要將這些事件以清晰的方式處理好了,我們的代碼自然會(huì)變得清晰起來。自然的,我們會(huì)想到觀察者模式。我們的處理程序都是用戶事件的接收者,訂閱了用戶的事件源,等到有事件源發(fā)出通知時(shí),我們的程序就會(huì)做出響應(yīng)。本著順勢而為的哲學(xué)思想,我們應(yīng)該用響應(yīng)式的思想來編寫代碼。

然后思考一個(gè)問題:我們編寫的代碼的本質(zhì)是什么呢?是一系列的處理函數(shù)。既然是函數(shù)的話,我們可以對(duì)計(jì)算機(jī)說:我想要這樣,然后想要那樣,最終我想得到的結(jié)果是這樣。而不是具體的告訴計(jì)算機(jī)你應(yīng)該先這樣,在那樣,最后在這樣。前者是函數(shù)式的思維,后者是命令式的思維。有點(diǎn)繞,舉一個(gè)直觀的例子吧:最近面試了一個(gè)實(shí)習(xí)生,讓他寫一個(gè)數(shù)組去重的代碼,他的實(shí)現(xiàn)如下:

實(shí)習(xí)生的數(shù)組去重代碼

他的思想就是告訴計(jì)算機(jī)你應(yīng)該先把這個(gè)數(shù)組遍歷一遍,然后把數(shù)組的值當(dāng)做map的鍵賦值給map,并初始化為1。然后遍歷這個(gè)map,取出它的鍵,push到數(shù)組中。返回這個(gè)數(shù)組。是不是感覺很麻煩。這就是命令式的思維。其實(shí)這個(gè)實(shí)現(xiàn)中有許多bug,比如給定數(shù)組arr要是有數(shù)字的話,轉(zhuǎn)換后的數(shù)組會(huì)把數(shù)字變成字符串。for in也會(huì)遍歷原型鏈上的值。想一想都覺得可怕。要是用函數(shù)式的思維呢?

函數(shù)式數(shù)組去重

是不是清爽許多。這段代碼的本質(zhì)是告訴計(jì)算機(jī):我想要把這個(gè)數(shù)組中除了第一個(gè)的相同的數(shù)過濾出去。簡潔明了,直接告訴計(jì)算機(jī)你想要什么就好。組合一些現(xiàn)有的函數(shù)來進(jìn)行語義化編程。只要一眼看上去就知道這段代碼想要表達(dá)什么。在監(jiān)聽到用戶的事件時(shí),只需要執(zhí)行一系列函數(shù),把處理后的結(jié)果給負(fù)責(zé)渲染view的庫就OK了。

那為什么函數(shù)式編程最近才變得火熱起來呢?這是一個(gè)歷史原因。當(dāng)時(shí)阿蘭圖靈和馮諾依曼祖師爺創(chuàng)立了計(jì)算機(jī)這門學(xué)科時(shí),因?yàn)槭情_天辟地的創(chuàng)造。所以最早一批學(xué)者都有著其他專業(yè)背景,但主要分為2大派:電子電氣和數(shù)學(xué)。它們帶來了不同的觀點(diǎn)。數(shù)學(xué)家提出的編程語言模型自然具有數(shù)學(xué)氣質(zhì),優(yōu)雅且易于管理,其中Lambda演算就是用純函數(shù)的組合來描述計(jì)算過程,如果一個(gè)問題能夠用一套函數(shù)組合的算法來描述,那么就說明這個(gè)問題是可計(jì)算的。但是當(dāng)時(shí)硬件制造技術(shù)很不發(fā)達(dá),電子元件制造成本又高,體積又大,無法在一個(gè)小芯片上放置多個(gè)元件。既然這樣,那只好省著點(diǎn)用了,命令式編程就這樣興起了。看過《喬布斯傳》的朋友們應(yīng)該知道,當(dāng)時(shí)喬布斯和沃森為了一款游戲減少幾個(gè)芯片的使用而耗費(fèi)精力。

隨著硬件技術(shù)的進(jìn)步,這些都不是問題了。所以數(shù)學(xué)家們提出的優(yōu)雅的解決方案慢慢的變得流行起來。

最后,我們得到了一個(gè)結(jié)論。web開發(fā)中根據(jù)用戶輸入處理這一步的解決方案即為函數(shù)式編程+響應(yīng)式編程。而這兩者結(jié)合起來即為函數(shù)響應(yīng)式編程。這正是Rx.js的思想。優(yōu)雅迷人。接下來讓我們一起揭開她美麗的面紗吧n(≧▽≦)n。


后記:如果想認(rèn)識(shí)一群有趣的人,經(jīng)歷一些有趣的事情的話,那么來酷家樂加入我們前端團(tuán)隊(duì)吧。簡歷可以發(fā)我郵箱:chonger@qunhemail.com,我來幫你內(nèi)推。另外秀一波我的無敵景觀工位:

無敵景觀工位
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容