前端體驗優化地最終目的就是讓用戶的使用體感舒適,無阻塞、流暢的得到預期想要的結果,而其中的用戶可分為三層:產品用戶、公司同事和研發自己。UX、性能優化其實都是體驗優化的子集,前端體驗猶如下圖的冰山那樣,在水下別有洞天。
:-: 
  可以將體驗優化大致分為 5 個模塊,分別是終端、網絡、前端、后端以及數據,這 5 個模塊可以形成一個閉環。
  終端就是瀏覽器、微信等一類設備,網絡就是緩存、協議等一類概念,前端和后端針對的就是技術細節,而數據其實就是最后的分析,對優化前后進行量化對比,最終得出結論,判斷此次優化是否成功。
  與以往的視覺體驗優化(例如線框圖的不同布局)不同,本文著重分析的前端體驗側重于技術端和數據分析,更偏向于前端開發人員,而不是 UI 設計人員。
:-: 
  下面是一張前端體驗優化的[思維導圖](https://github.com/pwstrick/daily/blob/master/assets/xmind/ux.xmind),還在持續更新中。
:-: 
  其中終端模塊的[圖像](http://www.hmoore.net/pwstrick/fe-questions/3131237)、[呈現](http://www.hmoore.net/pwstrick/fe-questions/3133382),[網絡模塊](http://www.hmoore.net/pwstrick/fe-questions/3139900),前端模塊的[JavaScript](http://www.hmoore.net/pwstrick/fe-questions/3136694)、[構建](http://www.hmoore.net/pwstrick/fe-questions/3146571)都被記錄在[前端性能精進](http://www.hmoore.net/pwstrick/fe-questions/3126322)專欄中。
  數據模塊的性能指標記錄在方法論之[測量](http://www.hmoore.net/pwstrick/fe-questions/3126323)和[分析](http://www.hmoore.net/pwstrick/fe-questions/3128806),監控體系記錄在[監控系統](http://www.hmoore.net/pwstrick/fe-questions/2363166)專欄內(包括[SDK](http://www.hmoore.net/pwstrick/fe-questions/2305450)、[存儲和分析](http://www.hmoore.net/pwstrick/fe-questions/2305451)、[頁面奔潰](http://www.hmoore.net/pwstrick/fe-questions/2363168))。
  終端優化的核心是減少渲染時間,網絡優化的核心是減少延遲時間,另外三個模塊都在服務于這兩個模塊。
  下圖描繪了網頁在加載過程中,各階段與上述模塊之間的優化關系。
:-: 
## 一、終端
  終端最常用的就是瀏覽器,瀏覽器最需要關注的優化點是兩個:圖像和呈現。
1. 在網頁中充斥著圖像,而圖像往往會增加網頁的尺寸,所以優化的重點是用盡手段減小尺寸,例如動態裁剪、響應式、WebP、加載時機的轉變等等。
2. 呈現涉及瀏覽器渲染和靜態資源的請求,核心就是縮短渲染和資源加載時間,例如只渲染首屏、提前加載后續資源、對重要資源優先請求等等。
  微信是一款國民級APP,提供了 JSSDK 和小程序的功能,JSSDK 賦予了用戶部分微信的能力,依托微信的生態,小程序現在有了非常廣泛的應用。所以對于這個環境,也會有各類獨特的優化手段,不過我本人還不熟悉這塊。
  還有一個很重要的終端就是各類 APP 內置的 WebView,客戶端通過 WebView 可以暴露出許多功能,幫助前端頁面的優化,例如喚起客戶端的登錄和支付界面,還有就是最大限度的緩存網頁資源,減少網絡請求,例如容器化、離線包。
  除此之外,還可以增加預請求的能力,將串行的網絡請求優化為并行的網絡請求,充分利用空閑時間。
  諸如 Electron、WebRTC、多媒體等這類優化點,自己并不是很熟悉,在此也不再贅述。
## 二、網絡
  當一個請求從終端發出到服務器接收,這段網絡傳輸的時間,其實是我們不可控的。
  要優化就只能從起點和終點兩處入手。最先想到的就是開啟緩存:強緩存和協商緩存。
  日常使用最多的是協商緩存,但是在性能提升上,決定強緩存更為明顯,因為強緩存后就不會再去服務器請求資源。
  不過,為了頁面正確,還得設法破壞緩存,尤其是 HTML 文件,例如給 URL 包一層短鏈,在請求時自動加個時間戳,以此讓緩存不再命中。
  HTTP 是一種網絡協議,目前已經可以廣泛使用 HTTP/2 協議,在之前的基礎上做了許多優化,例如二進制分幀層、多路通信、首部壓縮等,讓數據傳輸的更快以及更大限度的利用好帶寬。
  協議中的壓縮字段,默認都已經開啟,對于非媒體文件(例如 HTML、CSS、JavaScript 等)經過壓縮后,尺寸可減少 50%,甚至 80%。
  HTTP/3 協議解決了上一個協議的幾個問題,例如 TCP 隊首阻塞、網絡切換成本等,不過目前最大的問題還是支持度不夠,不能大范圍的使用。
  HTTPS 是 HTTP 的安全版本,目前有些瀏覽器默認會將 HTTP 的請求重定向到 HTTPS,這種多余的重定向完全可以避免。
  CDN 是一種網絡加速服務,目前有很多公司都提供了這類服務,但就是要花錢,只要花錢了,海外都能給你加速,無論靜態資源還是動態接口,都可以借助 CDN 加速,現在還能提供對圖像的動態裁剪和壓縮的功能。
  有時候瀏覽網頁會遇到網關報出的 500、502、503、504 等錯誤,其實就是服務異常、找不到轉發服務或轉發服務在指定時間內未響應。
  對于未響應,可以從相關分析平臺找出性能瓶頸,然后在后端部分進行代碼優化,很多時候與數據庫有關。無論如何,要盡一切可能避免此類錯誤,這類體驗最為糟糕,無法得到預期結果。
## 三、前端
  前端現在已經離不開工程化構建,常見的 Webpack、Rollup 等打包工具提供了許多優化功能,例如壓縮、合并、剪枝等,盡量減少網絡請求和資源尺寸。
  除此之外,盡量減少和選擇輕量級的依賴庫,也能降低不少的尺寸。隨著 IE 這個毒瘤退出舞臺,移動端興起之后,ES6 也被廣泛的支持,很多時候都沒必要降級到 ES5,再也不用平白無故的多出一大段代碼了。
  ESBuild 也是一個構建工具,不過與之前的不同,它內部是用 go 編寫的,所以說它非常快。
  Vite 的開發環境依賴的就是它,但是為了快,就沒有提供 AST 的操作能力,導致目前很多的插件無法使用,所以 Vite 生產環境使用的還是 Rollup,是對性能與靈活性的一種平衡。
  前端三劍客之一的 JavaScript,是每個前端開發人員每日必會使用到的,對于它的優化基本上都是代碼層面的優化,常見的節流和防抖,算法和數據結構,分解或異步執行長任務,本地存儲等。
  有個庫叫[Partytown.js](https://github.com/BuilderIO/partytown),比較有意思,可以將第三方腳本遷移到 Web Worker 中執行,防止阻塞主線程,不過這還只是個測試性的庫。
  前端為了讓自己的日常工作比較爽,技術棧不能太舊,否則很多新功能都體驗不到,太可惜了。在升級技術棧時,還不能影響業務,運營、產品等人可不會在意你用什么技術棧,他們在意的是業務保持穩定,并且還能持續迭代。
  前端的基建包括組件化、標準化、工具化、自動化、文檔化以及頁面規范化,本質就是讓自己組的開發效率能更高,與別人協作發生的錯誤能更少,產品上線后最好沒有問題。一句話就是你要好,大家也要好,和諧辦公。
  在功能上線前,可以對新功能加個開關,萬一有問題,就直接關閉新功能,粒度可以是頁面級別的。不過前端發版不像客戶端那么困難,畢竟做開關是要成本的。灰度和 A/B 測試,在前端也可以執行。
## 四、后端
  傳統的前端開發是不接觸后端的,但是自從 Node.js 拓寬了前端的邊界后,越來越多的前端開始涉足后端,那么就很有必要了解后端的體驗優化。
  后端的優化大致可分為兩部分:Node.js 和數據庫,對于它們的監控,市面上有許多成熟的平臺,自己搭建的話,成本有點高。
  我剛到公司時,還在用 Node.js 的 8.7 版本,明顯太老,在挑選第三方庫時,還得特地挑老版本,所以說,要將版本進行最適當的升級,在改造成本最小的前提下,升級到最高的那個版本。
  上一節講到基建,其中很多內容都是需要借助 Node.js 實現的,例如通用配置、腳本執行等。
  還有下一節中的監控系統,也需要 Node.js 實現,并且還要涉及到消息隊列、MySQL、ElasticSearch 等技術點。注意,對于那些非業務服務,需要單獨分離,以免異常時影響線上業務。
  在有了后端能力后,就能自己寫接口,接口的響應格式很重要,在統一后,更容易分析接口的成功和失敗細節。并且對于接口,要有安全意識,以及不能因為接口的問題而讓頁面直接異常,需要用更友好的反饋方式。
  目前市面上有許多種數據庫,常見的關系型數據庫 MySQL,遇到比較多的問題就是數據量上去后的慢響應,很可能導致 504 異常,要么縮小查詢范圍,要么就是創建合適的索引。
  MySQL 處理百萬級的數據量綽綽有余,但千萬級就比較夠嗆了,此時除了索引加持外,還需要進行分表、數據歸檔等手段,其實本質都是為了減少數據量。
  與之前的 Node.js 服務類似,對于那些非業務表,可以單獨生成一個庫來存儲,也是避免數據庫異常導致線上業務出錯。
  MySQL 全文檢索的能力不行,所以對于大數據量的全文檢索需要改用 ElasticSearch,還有那些需要聯多張表的情況,也可以將數據存儲到 ElasticSearch 中再做查詢。
  Redis 其實也是一種非關系型的數據庫,最大的特點就是快,若要對接口的查詢進行優化, Redis 無疑是一種高效的手段。
  不過在用 Redis 時需要注意,它只是一種緩存,若沒有它,也要能得到預期的數據。也就是說,盡量不要讓業務邏輯依賴 Redis 中的數據,Redis 只是為了加速,即使沒有了它,線上業務也不應該出錯。
## 五、數據
  為了能更好的優化體驗,很有必要量化性能,以及監控頁面的方方面面。
  首先關于性能,目前已有很多工具,例如 Lighthouse、WebPageTest 和 Chrome Devtools,它們會分析頁面的性能,不過這些只能算是實驗室數據,并不是真實用戶的數據。
  我們自研了性能監控系統,記錄了一系列的指標,包括白屏、首屏等,在搜集過后,提供了多種圖表進行性能分析。
  力圖重現真實用戶的使用場景,發現性能瓶頸。前端監控也是自研的,會記錄頁面的異常、通信、點擊等行為,同樣提供了各類圖表。
  通過此系統,可以主動發現頁面中的錯誤,而不是等待用戶上報,并且還發現了許多冗余接口。
  除此之外,每天都會推送核心指標到前端的飛書群中,包括接口慢響應占比、SLA(服務質量保證,即5XX占比)等,關注服務的健康度。
  線上還會實時監控頁面、接口和數據庫的錯誤情況,當達到某一個閾值時,就會發送告警到飛書中,同樣是為了在用戶上報前發現問題。
  為了能更好的與公司同事協作,我們組制訂的每雙月的需求提測率和用戶滿意度評分,當然,這個用戶是內部員工。
  之所以是提測率而不是完成率,是因為很多時候項目是要與服務端協作的,可能我們做完了,他們還沒完成,而這種情況還比較普遍,所以就使用了提測率。
  除了技術監控之外,前端人員還需要了解業務監控數據,其實也是為了讓自己能更好的理解業務,培養產品思維。
  通過埋點將某一處的動作,傳輸到服務器做存儲,然后再經過數據分析人員,繪制成一張張的圖表。埋點的采集并不復雜,常見的就是侵入式的在某一處位置加入埋點代碼。
  若對頁面做了某種優化,涉及到業務邏輯時,可以分析埋點數據,比對前后的變化,來決定優化是否成功。
  在我們公司,每一個小組都會有一個或兩個北極星指標(例如用戶新增數、XX營收、日志發布率等),指標的變化就是核心業務的變化。
  而在這個指標下面,還有許許多多的細節指標,支撐著北極星指標,以會員為例,日付費人數、日下單量、首次充值人數等。
  如果有條件的話,可以讓分析人員開放些與自己有關的指標,再與相關人員緊密溝通,讓這些數據更有活性。
*****
> 原文出處:
[博客園-前端體驗優化](https://www.cnblogs.com/strick/category/2360021.html)
[知乎專欄-前端性能精進](https://www.zhihu.com/column/c_1610941255021780992)
已建立一個微信前端交流群,如要進群,請先加微信號freedom20180706或掃描下面的二維碼,請求中需注明“看云加群”,在通過請求后就會把你拉進來。還搜集整理了一套[面試資料](https://github.com/pwstrick/daily),歡迎閱讀。

推薦一款前端監控腳本:[shin-monitor](https://github.com/pwstrick/shin-monitor),不僅能監控前端的錯誤、通信、打印等行為,還能計算各類性能參數,包括 FMP、LCP、FP 等。
- ES6
- 1、let和const
- 2、擴展運算符和剩余參數
- 3、解構
- 4、模板字面量
- 5、對象字面量的擴展
- 6、Symbol
- 7、代碼模塊化
- 8、數字
- 9、字符串
- 10、正則表達式
- 11、對象
- 12、數組
- 13、類型化數組
- 14、函數
- 15、箭頭函數和尾調用優化
- 16、Set
- 17、Map
- 18、迭代器
- 19、生成器
- 20、類
- 21、類的繼承
- 22、Promise
- 23、Promise的靜態方法和應用
- 24、代理和反射
- HTML
- 1、SVG
- 2、WebRTC基礎實踐
- 3、WebRTC視頻通話
- 4、Web音視頻基礎
- CSS進階
- 1、CSS基礎拾遺
- 2、偽類和偽元素
- 3、CSS屬性拾遺
- 4、浮動形狀
- 5、漸變
- 6、濾鏡
- 7、合成
- 8、裁剪和遮罩
- 9、網格布局
- 10、CSS方法論
- 11、管理后臺響應式改造
- React
- 1、函數式編程
- 2、JSX
- 3、組件
- 4、生命周期
- 5、React和DOM
- 6、事件
- 7、表單
- 8、樣式
- 9、組件通信
- 10、高階組件
- 11、Redux基礎
- 12、Redux中間件
- 13、React Router
- 14、測試框架
- 15、React Hooks
- 16、React源碼分析
- 利器
- 1、npm
- 2、Babel
- 3、webpack基礎
- 4、webpack進階
- 5、Git
- 6、Fiddler
- 7、自制腳手架
- 8、VSCode插件研發
- 9、WebView中的頁面調試方法
- Vue.js
- 1、數據綁定
- 2、指令
- 3、樣式和表單
- 4、組件
- 5、組件通信
- 6、內容分發
- 7、渲染函數和JSX
- 8、Vue Router
- 9、Vuex
- TypeScript
- 1、數據類型
- 2、接口
- 3、類
- 4、泛型
- 5、類型兼容性
- 6、高級類型
- 7、命名空間
- 8、裝飾器
- Node.js
- 1、Buffer、流和EventEmitter
- 2、文件系統和網絡
- 3、命令行工具
- 4、自建前端監控系統
- 5、定時任務的調試
- 6、自制短鏈系統
- 7、定時任務的進化史
- 8、通用接口
- 9、微前端實踐
- 10、接口日志查詢
- 11、E2E測試
- 12、BFF
- 13、MySQL歸檔
- 14、壓力測試
- 15、活動規則引擎
- 16、活動配置化
- 17、UmiJS版本升級
- 18、半吊子的可視化搭建系統
- 19、KOA源碼分析(上)
- 20、KOA源碼分析(下)
- 21、花10分鐘入門Node.js
- 22、Node環境升級日志
- 23、Worker threads
- 24、低代碼
- 25、Web自動化測試
- 26、接口攔截和頁面回放實驗
- 27、接口管理
- 28、Cypress自動化測試實踐
- 29、基于Electron的開播助手
- Node.js精進
- 1、模塊化
- 2、異步編程
- 3、流
- 4、事件觸發器
- 5、HTTP
- 6、文件
- 7、日志
- 8、錯誤處理
- 9、性能監控(上)
- 10、性能監控(下)
- 11、Socket.IO
- 12、ElasticSearch
- 監控系統
- 1、SDK
- 2、存儲和分析
- 3、性能監控
- 4、內存泄漏
- 5、小程序
- 6、較長的白屏時間
- 7、頁面奔潰
- 8、shin-monitor源碼分析
- 前端性能精進
- 1、優化方法論之測量
- 2、優化方法論之分析
- 3、瀏覽器之圖像
- 4、瀏覽器之呈現
- 5、瀏覽器之JavaScript
- 6、網絡
- 7、構建
- 前端體驗優化
- 1、概述
- 2、基建
- 3、后端
- 4、數據
- 5、后臺
- Web優化
- 1、CSS優化
- 2、JavaScript優化
- 3、圖像和網絡
- 4、用戶體驗和工具
- 5、網站優化
- 6、優化閉環實踐
- 數據結構與算法
- 1、鏈表
- 2、棧、隊列、散列表和位運算
- 3、二叉樹
- 4、二分查找
- 5、回溯算法
- 6、貪心算法
- 7、分治算法
- 8、動態規劃
- 程序員之路
- 大學
- 2011年
- 2012年
- 2013年
- 2014年
- 項目反思
- 前端基礎學習分享
- 2015年
- 再一次項目反思
- 然并卵
- PC網站CSS分享
- 2016年
- 制造自己的榫卯
- PrimusUI
- 2017年
- 工匠精神
- 2018年
- 2019年
- 前端學習之路分享
- 2020年
- 2021年
- 2022年
- 2023年
- 2024年
- 日志
- 2020