hello~親愛的看官老爺們大家好~有一段時間沒寫文章了,最近忙於為一個對內的資料視覺化平臺進行完全的前後端分離。原來的專案是一個基於 Vue
的單頁應用,重構後接入 Node
作為中間層,達到完全的前後端分離。
由於專案相對簡單,成本並不是太高。下文將簡單介紹一下使用的技術棧與分離後的收益,重點是對基於 Node
做前後端分離的一點思考。
背景
大約是去年11月底入職新東家,接手一個僅 對內 的資料分析系統。新入職當然是希望做出點成績,在更改部分 UI 與優化部分功能之後,發現頁面效能還是比較低。排查後發現獲取資料的介面沒有快取,也不是基於 RESTful
的,瀏覽器快取完全不起作用。期間也經歷了後端修改介面,前端程式碼大面積修改的情況。
基於後端同學不熟悉前端機制,我也抱著方便日後搞事情的心態,在多次滾地板之後,部門 Leader 同意接入 Node
作為中間層。
技術選型
在確定接入 Node
後,首先要做的就是技術選型。Node
一般就是在 Express
、Koa
與 Egg
中選。在中介軟體的使用上,個人偏好 Koa
,因而只好和 Express
說再見了 。Egg
是在 Koa
上作了強約束,規定程式碼編寫、目錄結構等。
選型時我與前端 Leader 討論了無數次,他認為 Egg
約束太多,擴充套件性較差,如若出現框架底層的 Bug 則難於處理,因而偏向於使用 Koa
。這樣的顧慮十分合理,然而對於現在的專案而言,不太可能有功能會超出 Egg
所提供的,反而 Egg
所提供的功能能為專案搭建與維護減少不少的成本。至於約束,個人認為這反而是一件好事,一定程度上解決了多人開發時程式碼的組織問題。
考慮再三後,決定使用 Egg
作為 Node
的框架。
分離收益
由於專案不算十分複雜,接入的過程算是波瀾不驚。唯一的麻煩是工期比較緊,因而分兩步走:一期先接入 Node
,所有頁端請求原樣轉發 Java
,返回的結果原樣轉發頁端。二期對資料獲取的介面進行整合與優化以提升效能。完成後收益還是客觀的,貼兩張圖展示下成果。
原來某頁面的效能(所有請求都是 Post 的):
接入 Node
相同頁面的效能(轉為方法為 Get):
可以看到,不論是資料下載量還是響應時間等指標,耗時均有降低。當然,這是建立在接入 Node
後我對介面進行了整合與快取優化等措施後的對比。如果都是首次訪問,公司內網 WiFi 環境下與原來的效能會有稍差一點,整體載入時間略高於 Java
直出50ms不到。也用過 Chrome 模擬弱網環境,耗時與 Java
直出基本一致。
而且開發體驗上也比之前舒服得多,算是達到了接入 Node
前定下的目標:接入後在支援相同功能的情況下效能提高30%;在相同的開發時間內,完成相同的需求,但有更好的開發體驗及更好的頁端效能。
小結一下,前端的一切優化都是在模板與獲取模板所需資料上進行優化,使用 Angular
、React
與 Vue
等框架構築的單頁應用,解決了模板的問題,可以不再讓後端去動我們的模板。但是獲取所需資料仍依賴於後端,不少單頁應用互動上已經足夠複雜,如果還需維護一套複雜的獲取與整合資料的邏輯,還是十分頭疼的。因而多接入一層 Node
處理資料的獲取與整合,盡最大努力去優化頁端的請求介面,讓頁端專注於互動,在條件成熟的情況下,是十分值得的。
思考
如若就為了推廣 Node
,本文應該是把上面的步驟寫詳細,小結完就該結束了,這和很多大佬的實踐文章一致(當然我寫得不夠好~)。然而和兩位 Leader 的討論過程中,感謝他們對 Node
技術抱有懷疑,提出了不少有意思的問題,結合我自己的思考,整理成提問形式呈現給大家。
為何接入
Node
作為中間層,和公司現行的PHP
有何區別?
沒有區別!事實說,Node
能做的 PHP
一樣能做。那麼問題就轉換為 Node
的意義是什麼,為何擯棄公司相對成熟的 PHP
方案而轉向 Node
?
我認為後端服務主要是穩定為主,業務調整不會特別頻繁。而對於前端而言,業務頻繁調整簡直司空見慣,如果前後端耦合在一起,頻繁讓後端發版不是可取之策。同時,前後端對資料結構的要求及對其控制的粒度也大不相同。寫得好 PHP
的同學不一定寫得好前端,寫得好前端的同學不一定寫得好 PHP
。對於專業的領域,還是應該由專業的人去做,讓前端控制整個模板及模板依賴的資料,對提高專案質量有很大的幫助。說句玩笑話,後端就搞搞資料庫,吐吐 json
就好,前端就拿一下資料,切切頁面就好。
進一步而言,前端若要接入 SSR
之類的功能,Node
還真比 PHP
有優勢得多,也算是為日後搞事情做鋪墊吧。
接入
Node
後效能會有多大提高?
不一定有提高,甚至有下降。此問題是我一期完成之後,測試頁端效能時發現的。測試時,Node
除了將所有的需求原樣轉發外,還加了協商快取,然而響應時間卻更慢了。
接入前(為 Post 請求):
接入後(為 Get 請求):
正常來說,獲取 10k 左右的資料時,協商快取如若命中即返回 304,省略了下載的過程,理應更快的。通過打點,發現 Node
轉發請求耗時額外增加 10ms 左右,然而在全公司內網 WiFi 環境下,整體下載時間不到 160ms。
因而引入 Node
不一定會有效能的提高,反而會因為多引入一層,而導致效能耗損。在對內的專案中或效能尚可的專案中,提高效能不足以成為接入 Node
的關鍵理由。換句話說,接入 Node
之後,在優化頁端請求之前,並不可能為應用效能帶來飛躍。
這個問題也算是我對 Node
態度轉變的起點,開始從無腦支援接入 Node
到辯證地推敲,也引出之後的的問題。
接入
Node
有什麼弊端?
前端的能力越強,意味著責任越多。例如之前可能是 Java
做的安全防護,可能就會下沉到 Node
端,這對大多數前端同學而已都是比較陌生的領域。
投入的成本與產出也是值得商榷的事情,畢竟 Node
再貼近前端,也始終是屬於後端的領域。前後端思想不太一樣,用前端的思維寫後端,很可能寫出十分糟糕的程式碼,輕則影響效能,重則記憶體洩漏。接入 Node
層後它反而成為拖累,相信大家也不願看見。
畢竟 Node
對於不少公司而言是比較新的領域。儘管可能知道接入 Node
好處不少,但如何接入,接入後它能做什麼,大家可能比較模糊。如何花最少的代價,平滑地接入 Node
的同時,最大限度的複用現有架構,也是個不少的挑戰。
既然如此,沒有
Node
適用的場景嗎?
有。正如前文所說,Node
的意義是在於讓前端掌握模板與模板所依賴資料,不妨從這兩方面去進行考慮。如若重 SEO 的同時,頁面互動相對複雜,這時候接入 Node
作為中間層,我認為就是最佳實踐。
其次是後端架構不斷演變,開始轉向微服務化之後,前端感到介面碎片化開始帶來不少麻煩後,就應該考慮接入 Node
整合介面了。
總的來說,什麼時候接入 Node
, 有點像什麼時候引入 Redux
或 Vuex
。當你感覺到麻煩後,只要你知道還有這個選項,自然而言地就會想到用它。
小結
綜上所述,在以下場景中,我認為接入 Node
是最佳實踐:
- 重視 SEO 且互動複雜。
- 後端微服務化,前端需要整合介面。
- 前端主導的專案,需要用到最新技術,如
SSR
、PWA
等。
如若只是效能問題,引入 Node
不一定會有改善,需要根據實際情況進行分析。至於後端的介面設計太醜陋、返回的資料結構不符合前端使用等問題,在應用規模不大的情況下,其實都是可以和後端同學進行溝通的,以此接入 Node
不一定是最佳的實踐,需要好好思量。
但是,堅決反對只是因為現有架構比較熟悉而不願改變,始終抱著錯誤的方案不去解決的做法,這絕對是捨本逐末。我始終認為,只要是對的事情,儘管過程再艱難,亦應該朝著對的方向前進。
以上是個人的一點淺見,感謝各位看官大人看到這裡。知易行難,希望本文對你有所幫助~謝謝!