一、背景
書接上文,淺談前後端分離與實踐(一) 我們用mock伺服器搭建起來了自己的前端資料模擬服務,前後端開發過程中只需定義好介面規範,便可以相互進行各自的開發任務。聯調的時候,按照之前定義的開發規範進行資料聯調便可以了。前後端的職能更加清晰:
後端 | 前端 |
---|---|
提供資料 | 接收資料,返回資料 |
處理業務邏輯 | 處理渲染邏輯 |
Server-side MVC架構 | Client-side MV* 架構 |
程式碼跑在伺服器上 | 程式碼跑在瀏覽器上 |
這裡分離乾淨了,分工也很明確了,看似一切都那麼美好,but...我們也很容易發現問題的所在:
- Client-side Model 是 Server-side Model 的加工
- Client-side View 跟 Server-side是 不同層次的東西
- Client-side的Controller 跟 Sever-side的Controller 各搞各的
- Client-side的Route 但是 Server-side 可能沒有
也就是說服務端和客戶端各層職責重疊,大家各搞各的,很難統一具體要做的事情。並且可能會伴隨著一些效能上的問題。最具體的表現就是我們常用的SPA應用:
- 渲染,取值都在客戶端進行,有效能的問題
- 需要等待資源到齊才能進行,會有短暫白屏與閃動
- 在移動裝置低速網路的體驗奇差無比
- 渲染都在客戶端,模版無法重用,SEO實現 麻煩
緊接著,我們程式碼量越來越大,我們需要校驗的表單也會越來越多,有時候,前端提交需要校驗一次表單。
服務端任需要進行校驗來達到資料的可靠性;前端的路由可能在服務端並不存在....等等這一系列重用性的問題。所以我們之前的重構可能需要更深層次的思考。
二、開始重構
在開始重構之前,我們需要對前後端界線做一個劃分,也就是說什麼是屬於前端的範疇,什麼是屬於後端的範疇,最傳統的前後端劃分可能是這樣的:
那麼問題來了:我們前後端劃分的接線,是依照工作職責來劃分的前後端;還是依照硬體環境劃分的前後端?自從了nodejs之後,我們可以從工作職能上重新定義前後端的範疇:
可以看到,這裡的前端比之前多了個nodejs,也就是在前後端之間我們構建了一個 nodejs 服務作為中間層!
為什麼我們選擇的中間層是nodejs呢?因為我們把中間層歸在了前端的範疇,那麼對前端小夥伴來說,nodejs畢竟還是個js,那麼從語法角度來說,上收起來應該沒有什麼問題。其次開發轉移成本也想對較低,不必來回切換語言的邏輯和語法:
- 前端熟悉的語言,學習成本低
- 都是JS,可以前後端複用
- 體質適合:事件驅動、非阻塞I/O
- 適合IO密集型業務
- 執行速度也不差
好了,提前說了這麼多東西,那麼這個中間層能給我們帶來什麼了?要知道引入nodejs的開發成本也是很大的,首先就是多了一層服務,多的不說,單憑傳輸時間,就多了一層的傳輸時間啊!下面我們來研究一下什麼應用場景下的nodejs能給我們帶來利大於弊的東西。
三、開始中間層之旅
引入nodejs之後,我們來重新劃分一下前後端的職能:
這個就是中間層nodejs的主要思路,下面我們來看一下常見的業務場景:
1. 介面資料可靠性修復
有的時候服務端返回給我們的資料可能並不是前端想要的結構,所有用到的展現資料都是後端通過非同步介面(AJAX/JSONP)的方式提供的,前端只管展現。但是後端經常提供後端的資料邏輯,在前端還需要去處理這些資料邏輯。比如我再開發一個功能的時候,有時候會碰到這樣的問題:
服務端返回的某個欄位為 null 或者服務端返回的資料結構太深,前端需要不斷寫這樣的程式碼去判斷資料結構是否真的返回了正確的東西,而不是個null 或者undefined:
if (params.items && params.items.type && ...) {
// todo
}複製程式碼
對於這種情況,我們前端其實不應該去重複校驗資料的格式,這也本不應該是瀏覽器端js需要做的事情。我們可以在中間層做介面轉發,在轉發的過程中做資料處理。而不用擔心資料返回的問題:
router.get('/buyer/product/detail', (req, res, next) => {
httpRequest.get('/buyer/product/detail', (data) => {
// todo 處理資料
res.send(data);
})
})複製程式碼
2. 頁面效能優化 和 SEO
有點時候我們做單頁面應用,經常會碰到首屏載入效能問題,這個時候如果我們接了中間層nodejs的話,那麼我們可以把首屏渲染的任務交給nodejs去做,次屏的渲染依然走之前的瀏覽器渲染。(前端換頁,瀏覽器端渲染,直接輸入網址,伺服器渲染)服務端渲染對頁面進行拼接直出html字串,可以大幅提高首屏渲染的時間,減少使用者的等待時間。這種形式應用最廣的比如 Vue 的服務端渲染,裡面也有相關的介紹。
其次對於單頁面的SEO優化也是很好地處理方式,由於目前的ajax並不被搜尋百度等搜尋引擎支援,所以如果想要得到爬蟲的支援,那麼服務端渲染也是一種解決方法。(PS:如果覺得服務端渲染太麻煩,我這裡還有一篇介紹處理SEO的另一種思路處理 Vue 單頁面 Meta SEO的另一種思路可以參考)
3. 淘寶常見的需求解決方案
需求:在淘寶,單日四億PV,頁面資料來自各個不同介面,為了不影響體驗,先產生頁面框架後,在發起多個非同步請求取資料更新頁面,這些多出來的請求帶來的影響不小,尤其在無線端。
解決方案:在NodeJS端使用 Bigpiper 技術,合併請求,降低負擔,分批輸出,不影響體驗。同時可以拆分大介面為獨立小介面,併發請求。序列 => 並行,大幅縮短請求時間。
4. 更多可能
結語
這裡只是提供問題的一種解決思路,還是那句話:一切看應用場景。如果你對本文內容有別的意見也歡迎一起交流探討。
關於
作者:monkeyWang
本人主頁:monkeyWang
本文部分圖片段落參考文章: 淘寶前後端分離實踐
微信公眾號:會不定期推送前端技術文章,歡迎關注