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