距離上次首頁改版,已有2年3個月五天。相較於上次改版對首頁整體框架、開發流程的大刀闊斧(前兩次改版總結傳送門:2016版,2017版),這次的改版看起來顯得有點像跳水——沒什麼水花。在站在巨人肩膀上的小巨人的叮嚀與期盼下,這次改版在延續17版的框架與流程的基礎之上,為首頁的穩定性、安全性、視覺體驗、無障礙體驗方面見縫插針地添了磚加了瓦。
本文將從以下幾個面向進行闡述
● 引入強型別校驗
● 升級資源建置方案
##● 接取自動化測試● 完善監控系統● 優化頁面載入體驗:骨架螢幕● 最佳化資訊無障礙體驗引入強型別類型校驗
在效能幾乎無懈可擊的情況下,我們決定從穩定性入手,為專案引入強型別校驗,彌補JavaScript 這種弱型別語言在不可預測性上的缺陷。 強型別語言 TypeScript 發佈6年有餘,國內應用程式的開發者也慢慢成長。一般來說,業務開發週期短,迭代頻繁,TypeScript 的引入對於很大一部分開發者來說是一件費時費力的事,用的話業務可以上線,不用的話業務照樣可以上線,因此團隊極少在業務生產中應用。但秉持著不折騰不凹凸的理念,新版首頁不負使命的,進行了基於 TS 的重構。 做 TS 重構並不難,把 js 字尾改成 ts 就好了。完。 當然是開玩笑的啦!顯然,這樣的 TS 是沒有意義的。只有嚴格遵循 TS 標準的代碼才能最大化 TS 的效用。在專案中,我們對TS 的檢查開啟strict 模式,每次提交時,都會對程式碼做一次完整的檢查,只要有TS 報錯就禁止提交,旨在向成員傳達一個訊息——寫強類型語言就該有覺悟,否則就是耍流氓。
沒有深入使用過 TS 的同學在前期可能會感到人生的艱難,但這些都是為你好為了保證代碼的健壯性。例如,在以往難以定位、查找的window 全域變數的管理上,十分令開發者頭疼,而引入了TS 之後,只要對全域變數進行了介面設置,各個元件中再也不會出現多餘或是未知全局變數的情況。再例如,在寫一個擁有get、set 方法的存貯類別的時候,TS 能幫助偵測取得內容的類型:interface MemoryState { testa: boolean testb: string } class Controller { state: StateType constructor() { this.state = { state: {}, } } get<K extends MemoryStateKeys>(key: K) { return this.state.memory[key] } set<K extends MemoryStateKeys>(key: K, value: MemoryState[K]): MemoryState[K] { this.state.memory[key] = value return value } }
升級資源建構方案
舊版首頁專案使用的建置工具Athena,推進了開發流程自動化,但是涉及到客製化的建置流程時,由於Athena 的通用性,不方便直接做改動。首頁包含直出、同步、非同步三種類型的資源引用,需對資源的打包進行特殊處理,所以我們這次回歸Webpack,基於Webpack 4.0 做了以下的方案優化:發布流程最佳化
舊版的發布流程中,每次發布需要對改動的檔案進行diff 檢查,避免產生不符合預期的誤改動。 Webpack 預設打包機制的特點,是根據模組的打包順序為每個模組提供一個依序編號的 ID,對檔案的套件進行依賴管理。舊版首頁的入口檔案包含依賴套件管理的執行環境,因此任何一個套件引入順序變更時,入口檔案都會變更。以上的打包機制會出現一個檔案發生引入順序變動時,可能會影響到編譯後的幾個甚至十幾個檔案發生變動的情況,而這些檔案中的邏輯程式碼部分其實並不需要更新,這就降低了diff 代碼的準確性,使得這項中間檢查措施失去了原本的意義。首頁快取機制與資源懶加載機制使得靜態資源在發佈時,需要對發生變動的檔案進行CDN 快取清除的操作,也就意味著,改動檔案越多,需要清除的快取資源連結就越多,而連結越多,由於快取清除不同步所造成的資源非同步載入出錯的機率就越高,每次上線發布都存在一定的風險。為了減少發布風險,新版首頁的打包機制改變了Webpack 的打包邏輯,透過設置,每個模組不再透過順序編號的ID 管理依賴包,而是透過檔案目錄產生哈希編碼的專有ID ,並把依賴套件的執行環境從入口文件中抽離出來作為一個單獨的資源請求,這樣每次改動文件時,可以只針對改動的文件diff,剔除了其他非預期的diff 情況。透過新的建置方案,使程式碼改動控制在預期的範圍內,確保部署流程的穩定性。
專案架構最佳化
舊版頁面的效能最佳化方案中,包含了部分js 片段直出,這些程式碼是專案所依賴的基底函數,需要在核心js 程式碼執行之前啟動。但這樣的方案也有一些不盡人意的地方:
● 由於程式碼需要直出於頁面模版中,考慮到相容性,這些程式碼不能使用一些高階語法,每次變更都需要確保自己的程式碼沒有相容問題,導致維護成本巨高。同時,首頁頁面模版由後台負責管理,直出程式碼的改動需經過後台發布,迭代成本略高,風險也不小;
#● 由於打包的限制,核心程式碼與模板程式碼存在同一套公用程式碼,程式碼冗餘不說,一旦這部分程式碼發生變動還需要同時修改與發布兩部分的程式碼,使得程式碼的維護成本增加。
針對上述問題,新版中我們將這些程式碼重新放入核心程式碼,模板程式碼中不再承載任何邏輯程式碼,迭代發版不再涉及模版發布,只需進行靜態資源的發布即可,開發過程中統一使用JS 高階語法,去除人工維護相容語法程式碼的過程。
至此,我們透過增強資源打包的可預測性、以及優化專案資源架構兩個面向對資源的發布方案進行了最佳化。
存取自動化測試
一個頁面開發完成後,在對其進行提測之前,對頁面進行自測是一個必不可少的環節。一方面,確保頁面所開發的功能能正常運作;另一方面,保證在對一個功能進行開發時,並沒有影響到頁面其他區域功能的正常使用。
一般情況下,自測需要人為手動地進行測試,但這樣會有兩個缺點,第一,需要測試的區域數量過於巨大,相似的測試操作過於頻繁,浪費了人力,也影響了測試的效率;第二,人為的自測由於沒有統一的自測規範,因此在測試時很容易有所疏漏,從而忽視了一些看似微小,實則影響巨大的bug,花費了大量的時間,卻得不到自測所需要的效果。針對這種情況,我們產生了實施自動化測試的想法。以新版首頁為例,我們透過使用 Nightwatch.js,為新版首頁建立了一個自動化測試腳本,對新版的首頁的73項用例進行自動化測試。
結果顯示,透過自動化測試,在不到三分鐘的時間內,完成了對新版首頁73項用例的測試,這也意味著,若要透過自動化測試,來對任一頁進行自測,自測的時間都可控制在五分鐘以內,且準確度更高。將自動化測試套用在發布前以及上線後5分鐘內,及時檢查測試案例,確保每次發版的安全。
完善監控體系
舊版頁面的前端監控系統覆蓋了瀏覽器資訊、頁面載入測速、樓層隱藏方面,但資訊通知較為滯後,且僅覆蓋了頁面onLoad 時間,收到警告訊息時,無法做到快速定位問題。
參考京東購物小程式目前的監控機制,新版首頁針對程式碼報錯、介面可用性增加了回報監控。
程式碼報錯監控:BadJS
透過 BadJS 框架擷取頁面報錯,並分析處理報錯資訊上報至京東 BadJS 服務。透過上報數據,我們可以得到報錯的詳細資訊以及發生次數。透過分析上報數據,可以發現一些潛在的問題,及時修復,確保首頁程式碼的健全性。同時根據上報數,還可以預估出一個問題所造成的影響範圍,以便預估損失。
業務可用性監控
這次改版,在可用率回報系統中為首頁補充了特定判定規則,包含呼叫次數、可用率、和TP(效能指標)三個維度,在此基礎上還可以對這三個維度進行環比,以減少誤報的可能性,近期系統還上線了紅燈告警-語音通知功能。
可用率上報系統一般被用來監聽接口可用性,但對於首頁來說,除了接口,還需關注樓層隱藏的情況。目前的兜底方案中,每個樓層中的模組介面兜底全部失效的情況下,會隱藏目前樓層。樓層一旦發生隱藏,則表示出現了比較嚴重的問題,需快速注意並解決。可用率上報系統可做到觸發告警規則時,1分鐘內即推送通知,精確到接口,便於及時發現問題,及時止損。要注意的是,如何設定一套能夠較為精確反映問題發生、減少假警報的閾值尤為重要,畢竟狼來了喊多了,也就等於沒有監控。
測速上報
這一部分延用了舊版的Athena 測速上報方案,並對一些與業務數據上報重複的部分做了減法,同時增加了接口的測速上報,完善故障追溯資料體系。
優化頁面載入體驗:骨架螢幕
舊版頁面懶載入的佔位方案採用了統一區域loading 動畫的方式,這種方式的優勢在於復用成本低,適配性強。但如果遇到較大面積的模組或模組較為密集的情況時,區域loading 動畫的體驗有所下降————要么是空白區域過大,要么是loading 動畫過於密集,模組加載過程造成的視覺差異感知較為明顯。而對於 PC 首頁來說,空白區域過大是主要存在的問題。
#低網速下舊版首頁的loading 體驗
#這次改版,我們引入了骨架屏方案,最終目的是以灰色豆腐塊的形式盡量縮小真實模組結構與加載佔位之間的視覺差異。執行起來可以依視覺差異分為兩種對應關係:
● 弱對應關係:只對模組進行標題、子項等主要內容進行塊化處理,復用性較高,適配性中等;
● 強對應關係:以視覺效果為基礎,對子項進一步作出圖片、文案的塊化處理,針對佔位面積較大、內容較複雜的子項進行較細化的塊化拆分,復用性低,適配性高。
考慮到首頁的特殊性,我們最終選擇了強對應關係的骨架屏方案,並為了可擴展性,使用的是使用樣式渲染的骨架屏,而不是直接使用圖片佔位。除了開發成本的上升,頁面首屏載入程式碼量也有所增加。
專案結構
#使用骨架螢幕所要達到的效果包含以下幾點:
● 提前佔位,在頁面的載入中捲軸不會發生較為明顯的跳動;
● 頁面快速滾動時也能看到骨架螢幕樣式的佔位。
也意味著骨架螢幕的內容需要與頁面做同步加載處理,結合懶加載組件,骨架屏幕組件需提前作為loading 結構傳入,並保證樣式在頁面渲染的第一時間進行加載,否則就失去了骨架螢幕的意義。
每個需要骨架螢幕樣式的元件,單獨分割出一個 placeholder 元件。組件內的佔位結構包含兩類樣式-顏色與尺寸定位,加上容器外層的動畫效果樣式。顏色樣式全頁公用,尺寸定位樣式與正式組件公用:
尺寸定位樣式與正式組件公用的目的是為了在將來組件樣式變更時,確保骨架螢幕與正式樣式的統一修改,避免出現樣式修改上的遺漏,但同時增加了樣式的維護成本。同時樣式編寫與分割的過程中也需要開發者註意相容骨架螢幕的樣式,例如需要佔位豆腐塊的容器間距 padding、margin 的選擇都很重要。因此這次首頁的骨架螢幕嘗試並不適合快速復用至其他項目。
#新版首頁骨架螢幕loading 體驗
最佳化訊息無障礙體驗
網路資訊無障礙,即針對視力障礙人士所提供的輔助。系統層級的輔助主要依賴讀螢幕工具,讀螢幕工具可以解決網頁端資訊無障礙 60%的阻礙,剩餘的 40%需要在網頁開發的過程中由開發者進行體驗優化。
沒有做任何資訊無障礙處理的網頁,使用讀屏工具訪問時一般存在以下幾個問題:
● 多餘無用資訊的播報,例如:跳轉連結、圖片名稱;
● 彈出浮層無法存取;
● 懶載入內容直接跳過;
為了造福國內一百一十人中的一個視障人士(資料來自這裡) ,本次改版,我們決定在PC 首頁開啟京東商城桌面端首個資訊無障礙實踐。
桌面端視障用戶的操作主要透過鍵盤進行。針對剛才提出的幾個問題,PC 首頁初步的無障礙體驗最佳化方案分為幾個階段。
第一階段,語意化一切tab 可及的元素-包含頁面外跳轉連結的a 標籤統一加入aria-label屬性,以便讀屏軟體能夠簡化讀取元素資訊;
第二階段,保證頁面主要模組的存取-懶加載內容佔位容器將tab-index 設定為大於0 的值,使得tab 鍵能夠遍歷到,以便觸發頁懶加載,避免tab 直接跳過;
##第三階段,擴展帶彈出浮層等元素的操作-針對無障礙增加彈出浮層互動邏輯,入口增加aria-haspopup 屬性,告訴讀屏軟體這裡是彈出浮層的入口,將tab-index 設定為大於0 的數值使得tab 操作可聚焦到,浮層彈出後焦點自動聚焦至浮層;
##第四階段,為視障用戶額外增加快速跳轉-參考Google 搜尋結果頁,可在頁面的頂部,增加一些隱藏的快速跳躍。 PC 首頁本次對搜尋框以及底部的「為你推薦」位置增加了隱藏跳轉鏈接,只有使用鍵盤操作的用戶能夠定位到。 對於商城頁面來說,第一階段能滿足基本的內容訪問,而如果能做到第四階段,才能算一個完整的資訊無障礙網站。商城業務中,無障礙體驗一直缺乏相應的規範與測試流程,因此透過本次PC 首頁的改版實踐,輸出了一份針對商城頻道頁的資訊無障礙開發規範,內容包含:
● 存取路徑設計規範
● 語意化規範
● 讀螢幕測試規範
未來將藉由這份規範,陸續實現商城其他業務的無障礙體驗最佳化。
綜上,本次改版對於開發者來說最大的變化,就是本地開發體驗更加舒適、發布風險有所降低、故障追溯更加完善,而對用戶來說,頁面加載跳動感大大減小,視障用戶的體驗終於得以照顧。作為商城桌面端的入口與門面,首頁的改進一定不止於此,希望每一次的改版都能有一絲的優化,使得首頁這個項目趨近完美。