什麼是單頁應用
所謂單頁應用,指的是在一個頁面上整合多種功能,甚至整個系統就只有一個頁面,所有的業務功能都是它的子模組,通過特定的方式掛接到主介面上。它是AJAX技術的進一步昇華,把AJAX的無重新整理機制發揮到極致,因此能造就與桌面程式媲美的流暢使用者體驗。
單頁應用的優勢
操作體驗流暢,媲美本地應用的感覺,切換過程中不會頻繁有被“打斷”的感覺。
因為介面框架都在本地,與服務端的通訊基本只有資料,所以便於遷移,可以用比較小的代價,遷移成桌面產品,或者各種移動端Hybrid產品。
單頁應用的弱點
- 對搜尋引擎不友好
- 開發難度相對較高
如何儘可能增強單頁應用的操作體驗?
- 路由的規劃
- 推送的使用
- 斷線重連機制
- 操作補償機制
- 本地快取
- 熱更新
- 良好的記憶體管理
- 服務端預渲染
1. 什麼叫做路由?
路由可以理解為url與介面狀態的對應關係。
我們需要注意到,在理想狀態下,url和介面狀態應當是精確對應的。比如說,對同一個使用者來說,兩次使用同一個url所開啟的介面,其狀態應當是完全一致的。對於同一個介面,進行相同的操作之後,url應當能夠精確反饋當前狀態。
但是我們需要注意到,細碎操作如果都需要跟路由保持同步,會是一個非常繁瑣的事情,所以在設計過程中應當加以取捨,捨棄那些過於細碎的狀態與路由的同步。
2. 服務端推送
推送的意思是,某些情況下,即使頁面開著不動,服務端也主動傳送訊息過來,讓介面能夠有所體現。通常我們會使用WebSocket之類的技術來實現這種體驗。
有時候,我們可能會看到一些在頁面上使用推送的場景,最常見的是即時訊息。
比如說,我們在應用里加一個聊天視窗,其他人發一條訊息,自己這邊能夠實時展現出來。
如果是為了極致的使用者體驗,我們可以把整個應用的業務變更都使用推送,比如:
我在檢視某條任務的時候,有人修改了這條任務,我這裡應該不需要做什麼操作,就能自動體現出他的修改。
如果對全業務的變更都做推送管理,使用體驗會大為加強,但是,實現難度和程式碼複雜度會急劇上升。
3. 斷線重連機制
我們如何判斷一個單頁面產品的技術水準呢?可以通過這樣一種方式:
連續開幾天不關,不需要通過“重新整理”這個操作來解決一些常見問題。
為什麼這個事情能夠體現技術水準呢?因為要把這個事情做到極致,需要把這幾件事情做好:
- 斷線重連機制
- 良好的記憶體管理
- 版本的自動升級
因為移動辦公普及之類的情況,導致我們可能需要面對一些情況,比如,切換了網路,電腦休眠再開啟之類,當再次聯網的時候,就需要去重新連結,並且,對這個過程中發生的業務變更進行“補課”,然後逐一應用到介面上來,把介面調整到最新狀態。
4. 操作補償機制
什麼是操作補償呢?
從邏輯上來講,當我們在介面上操作,建立一條任務的時候,新的這條任務不應當立刻顯示出來,而是應當等到服務端確認成功了,才加到介面上。但很可能我們的網路不好,這一步使用者要等很久。從使用者體驗的角度,這樣是不好的,所以我們可以先把介面放上去,然後等建立成功的訊息回來之後,再把一些唯一標識之類的東西回填到記憶體資料中。
單步的操作補償還算是不太難,如果有多步的話,就非常麻煩了,舉個極端情況的例子來說,使用者新增了一條任務,服務端還沒返回的時候,他就立刻在這條任務下建立子任務,但子任務這時候沒有父任務的id,如果想給這步也做操作補償,就比較麻煩了。甚至說,連續進行了幾步操作之後,發現之前的操作失敗了,後續處理會非常複雜。
5. 本地快取的使用
上面提到,如果多步連續操作中間出現了失敗,局面會比較尷尬,比如你填了好多東西,提交的時候才發現網路壞了,那就非常頭疼,這時候,使用者會非常期望這些資料能夠儲存下來,等網路好了再重新嘗試。
我們可以使用本地快取來臨時儲存這些資料。如果這個層面做到極致,能夠結合良好設計的操作補償機制,甚至可以讓使用者離線使用我們的應用,把所有產生的這些變更都快取,等到聯網的時候再批量同步合併回去。
6. 熱更新
前面提到,使用者有可能長期開著我們的應用,然後中間一直沒有重新整理。正常情況下,業務變更都應當會被全部推送過來,介面所反饋的狀況始終是最新的,符合現狀的。但我們需要考慮到另外一個問題,系統升級怎麼辦?
我們當然可以推送一個通知:本系統已經升級了,請點選重新整理。但能不能做得更好?這是有可能的,要達到這種目的,就要使用熱更新這種手段,把程式碼的模組化和變更管理都做到極致,每次更新的程式碼模組也推送過來,並且作為補丁應用到當前系統上。這種機制對開發團隊的水準要求很高。
7. 良好的記憶體管理
要想讓使用者能夠長期開著應用,還需要管理好記憶體。
資料的變動、路由的切換、元件的建立與銷燬,都會帶來記憶體的變化。完美的記憶體控制是幾乎做不到的,如果要追求這方面的極致,對開發過程的影響會非常大,很多情況下是不划算的,所以,可以做一些針對優化,把比較常規的問題解決掉,不用的東西及時銷燬。
8. 服務端預渲染
作為一個單頁應用,很經典的模式就是前後端完全分離,前端載入介面和邏輯,後端響應資料,前端根據這些資料,“生成”相應的變化。
注意到,我們這裡有一個“生成”的過程,通常我們也會把這個過程稱為“渲染”。它的機制就是根據資料生成對應的介面,如果是在瀏覽器側生成這個介面,首先,載入介面模板或者邏輯,需要一次請求,然後,等這塊準備好了,還需要去請求資料,這時候又多了一次網路請求。網路請求通常是比“生成介面”慢的,並且很可能這個時間不穩定,這時候就可能延誤了使用者第一次看到介面的時間。
雖然單頁應用跟服務端渲染是存在矛盾的,但我們仍然可以部分優化這個事情,比如把某些頁面由服務端直接代入資料生成。現在有一些開發框架也在嘗試從另外一個層面解決這個問題,那就是對客戶端和服務端渲染提取共性,使用合適的抽象方式來同時描述這兩種機制,從而僅僅依靠配置的變更就可以切換渲染機制。
小結
我們提到了這些能夠提升單頁應用體驗的方式,如果實現出來,肯定是可以讓使用者非常愉悅的,但需要冷靜權衡理想與現實之間的差距:
- 我要做的是一個怎樣的東西?
- 我的開發團隊是怎樣的實力?
- 我們有怎樣的歷史負擔?
- 值不值得這麼做?
- 能不能做得了?
本文中提到的這些體驗增強方式,都是需要去權衡實現的,做得越多,所需要的技術掌控能力越強,出錯概率也越高。
有一句著名的表示式:
E = MC^2
我們可以對此有不一樣的解讀:
1 |
Errors = (More Code) ^ 2 |