## 寫在小冊的半山腰
不知不覺,小冊內容已經過了小半了。
回顧一下走過的路:在對知識體系進行一番梳理后,我們操起 webpack 開始優化文件(順便還學了點 Gzip),隨后又馬不停蹄進入圖片的小天地,最后把緩存和本地存儲的味道逐一品嘗,終于得以窺見網絡層面核心優化技術的全貌。
古人云:學而不思則罔。
站在性能優化的半山腰,我希望大家可以緩一緩,停下來思考一個問題:我得到了什么?
作為作者,我在自己寫的每一行字背后都費了思量。在過去的每個章節里我都預先為知識點做了權重劃分,力求“詳略得當”,而非盲目地求大求全。孰詳孰略,只能根據知識點本身的重要性來劃分,但讀者的知識結構是多樣的。“如何使閱讀效益最大化”的金鑰匙不在我手中,而是在各位自己手中。
本小冊中我有所提及的每一個知識點,**都有大公司在實踐**。即便是略寫的內容,大家也值得進一步去推敲。可以嘗試深挖這本小冊的可能性,把它用起來,用到自己的工作中去,去看看它能否給你的業務帶來提升,看看是否還有更精進的方案。
我是一個“啰嗦”的人。尤其是意識到這本書可能會成為一些同學的性能優化啟蒙讀物時,我更加認為有必要在行文小半時再啰嗦這么一遍:如果讀到這里,腦海中無法復現出網絡層面的知識體系,無法在回憶每個技術點時記起它的場景和特性,我建議不要急于往下走,而是回過頭去再看看學過的這部分的內容——走馬觀花不是學習,主動理解+動手實踐才是。
## 彩蛋:CDN的緩存與回源機制解析
> CDN (Content Delivery Network,即內容分發網絡)指的是一組分布在各個地區的服務器。這些服務器存儲著數據的副本,因此服務器可以根據哪些服務器與用戶距離最近,來滿足數據的請求。 CDN 提供快速服務,較少受高流量影響。
### 為什么要用 CDN
瀏覽器存儲的相關知識此刻離我們還不太遠,大家趁熱回憶一下:緩存、本地存儲帶來的性能提升,是不是只能在“獲取到資源并把它們存起來”這件事情發生之后?也就是說,首次請求資源的時候,這些招數都是救不了我們的。要提升首次請求的響應能力,除了我們 2、3、4 節提到的方案之外,我們還需要借助 CDN 的能力。
### CDN 如何工作
借中國地圖一角來給大家舉一個簡單的??:

假設我的根服務器在杭州,同時在圖示的五個城市里都有自己可用的機房。
此時有一位北京的用戶向我請求資源。在網絡帶寬小、用戶訪問量大的情況下,杭州的這一臺服務器或許不那么給力,不能給用戶非常快的響應速度。于是我靈機一動,把這批資源 copy 了一批放在北京的機房里。當用戶請求資源時,就近請求北京的服務器,北京這臺服務器低頭一看,這個資源我存了,離得這么近,響應速度肯定噌噌的!那如果北京這臺服務器沒有 copy 這批資源呢?它會再向杭州的根服務器去要這個資源。在這個過程中,北京這臺服務器就扮演著 CDN 的角色。
### CDN的核心功能特寫
CDN 的核心點有兩個,一個是**緩存**,一個是**回源**。
這兩個概念都非常好理解。對標到上面描述的過程,“緩存”就是說我們把資源 copy 一份到 CDN 服務器上這個過程,“回源”就是說 CDN 發現自己沒有這個資源(一般是緩存的數據過期了),轉頭向根服務器(或者它的上層服務器)去要這個資源的過程。
### CDN 與前端性能優化
一個彩蛋的自我修養——CDN 往往是被前端認為前端不需要了解的東西。
具體來說,我身邊許多同學對其的了解止步于:部署界面上有一個“部署到CDN”按鈕,我去點一下,資源就在 CDN 上啦!
“眼下業務開發用不到的可以暫緩了解”,這是沒毛病的。但正如我小冊開篇所說的,前端工程師首先是軟件工程師。對整個技術架構的理解,將會反哺我們對某一具體環節的理解;知識點的適當拓展,也會對大家技術高度和技術廣度的提升大有裨益。
那么,我們了解一下 CDN 是怎么幫助前端的。
**CDN 往往被用來存放靜態資源**。上文中我們舉例所提到的“根服務器”本質上是業務服務器,它的核心任務在于**生成動態頁面或返回非純靜態頁面**,這兩種過程都是需要計算的。業務服務器仿佛一個車間,車間里運轉的機器轟鳴著為我們產出所需的資源;相比之下,CDN 服務器則像一個倉庫,它只充當資源的“棲息地”和“搬運工”。
所謂“靜態資源”,就是像 JS、CSS、圖片等**不需要業務服務器進行計算即得的資源**。而“動態資源”,顧名思義是需要**后端實時動態生成的資源**,較為常見的就是 JSP、ASP 或者依賴服務端渲染得到的 HTML 頁面。
什么是“非純靜態資源”呢?它是指**需要服務器在頁面之外作額外計算的 HTML 頁面**。具體來說,當我打開某一網站之前,該網站需要通過權限認證等一系列手段確認我的身份、進而決定是否要把 HTML 頁面呈現給我。這種情況下 HTML 確實是靜態的,但它**和業務服務器的操作耦合**,我們把它丟到CDN 上顯然是不合適的。
### CDN 的實際應用
靜態資源本身具有訪問頻率高、承接流量大的特點,因此靜態資源加載速度始終是前端性能的一個非常關鍵的指標。CDN 是靜態資源提速的重要手段,在許多一線的互聯網公司,“靜態資源走 CDN”并不是一個建議,而是一個規定。
比如以淘寶為代表的阿里系產品,就遵循著這個“規定”。
打開淘寶首頁,我們可以在 Network 面板中看到,“非純靜態”的 HTML 頁面,是向業務服務器請求來的:

我們點擊 preview,可以看到業務服務器確實是返回給了我們一個尚未被靜態資源加持過的簡單 HTML 頁面,所有的圖片內容都是先以一個 div 占位:

相應地,我們隨便點開一個靜態資源,可以看到它都是從 CDN 服務器上請求來的。
比如說圖片:

再比如 JS、CSS 文件:


### CDN 優化細節
如何讓 CDN 的效用最大化?這又是需要前后端程序員一起思考的龐大命題。它涉及到 CDN 服務器本身的性能優化、CDN 節點的地址選取等。但我們今天不寫高深的論文,只談離前端最近的這部分細節:CDN 的域名選取。
大家先回頭看一下我剛剛選取的淘寶首頁的例子,我們注意到業務服務器的域名是這個:
```
www.taobao.com
```
而 CDN 服務器的域名是這個:
```
g.alicdn.com
```
沒錯,我們不一樣!
再看另一方面,我們講到 Cookie 的時候,為了凸顯 Local Storage 的優越性,曾經提到過:
> Cookie 是緊跟域名的。同一個域名下的所有請求,都會攜帶 Cookie。大家試想,如果我們此刻僅僅是請求一張圖片或者一個 CSS 文件,我們也要攜帶一個 Cookie 跑來跑去(關鍵是 Cookie 里存儲的信息我現在并不需要),這是一件多么勞民傷財的事情。Cookie 雖然小,請求卻可以有很多,隨著請求的疊加,這樣的不必要的 Cookie 帶來的開銷將是無法想象的……
同一個域名下的請求會不分青紅皂白地攜帶 Cookie,而靜態資源往往并不需要 Cookie 攜帶什么認證信息。把靜態資源和主頁面置于不同的域名下,完美地避免了不必要的 Cookie 的出現!
看起來是一個不起眼的小細節,但帶來的效用卻是驚人的。以電商網站靜態資源的流量之龐大,如果沒把這個多余的 Cookie 拿下來,不僅用戶體驗會大打折扣,每年因性能浪費帶來的經濟開銷也將是一個非常恐怖的數字。
如此看來,性能優化還真是要步步為營!
## 小結
結束了對 CDN 的剖析,我們網絡層面的優化之旅也終于告一段落了。接下來等待大家的就是另一個龐大的知識板塊——渲染層面的挑戰。
與其說是“渲染層面的優化”,不如說是“瀏覽器端的優化”。這個板塊旨在要大家對瀏覽器及其相關運行機制“知根知底”,進而通過具體的代碼片段學習代碼層面的應用手段。這部分是實打實的“硬骨頭”,需要大家花些精力。
過去的幾個小節里,我們考慮了服務端,考慮了網絡,考慮了協議。那么接下來,我們就以“服務端渲染”為引子,承上啟下,切入瀏覽器渲染的世界。
- 開篇:知識體系與小冊格局
- 網絡篇 1:webpack 性能調優與 Gzip 原理
- 網絡篇 2:圖片優化——質量與性能的博弈
- 存儲篇 1:瀏覽器緩存機制介紹與緩存策略剖析
- 存儲篇 2:本地存儲——從 Cookie 到 Web Storage、IndexDB
- 彩蛋篇:CDN 的緩存與回源機制解析
- 渲染篇 1:服務端渲染的探索與實踐
- 渲染篇 2:知己知彼——解鎖瀏覽器背后的運行機制
- 渲染篇 3:對癥下藥——DOM 優化原理與基本實踐
- 渲染篇 4:千方百計——Event Loop 與異步更新策略
- 渲染篇 5:最后一擊——回流(Reflow)與重繪(Repaint)
- 應用篇 1:優化首屏體驗——Lazy-Load 初探
- 應用篇 2:事件的節流(throttle)與防抖(debounce)
- 性能監測篇:Performance、LightHouse 與性能 API
- 前方的路:希望成為你的起點