打開(kāi)一個(gè)頁(yè)面的過(guò)程有很多優(yōu)化點(diǎn),包括前端和客戶端,常規(guī)的前端和后端的性能優(yōu)化在桌面時(shí)代已經(jīng)有醉佳實(shí)踐,主要的是:
降低請(qǐng)求量:合并資源,減少 HTTP 請(qǐng)求數(shù),minify / gzip 壓縮,webP,lazyLoad。
加快請(qǐng)求速度:預(yù)解析DNS,減少域名數(shù),并行加載,CDN 分發(fā)。
緩存:HTTP 協(xié)議緩存請(qǐng)求,離線緩存 manifest,離線數(shù)據(jù)緩存localStorage。
渲染:JS/CSS優(yōu)化,加載順序,服務(wù)端渲染,pipeline。
其中對(duì)首屏啟動(dòng)速度影響醉大的就是網(wǎng)絡(luò)請(qǐng)求,所以優(yōu)化的重點(diǎn)就是緩存,這里著重說(shuō)一下前端對(duì)請(qǐng)求的緩存策略。我們?cè)偌?xì)分一下,分成 HTML 的緩存,JS/CSS/image 資源的緩存,以及 json 數(shù)據(jù)的緩存。
HTML 和 JS/CSS/image 資源都屬于靜態(tài)文件,HTTP 本身提供了緩存協(xié)議,瀏覽器實(shí)現(xiàn)了這些協(xié)議,可以做到靜態(tài)文件的緩存,具體可以參考這里,總的來(lái)說(shuō),就是兩種緩存:
詢問(wèn)是否有更新:根據(jù) If-Modified-Since / ETag 等協(xié)議向后端請(qǐng)求詢問(wèn)是否有更新,沒(méi)有更新返回304,瀏覽器使用本地緩存。
直接使用本地緩存:根據(jù)協(xié)議里的 Cache-Control / Expires 字段去確定多長(zhǎng)時(shí)間內(nèi)可以不去發(fā)請(qǐng)求詢問(wèn)更新,直接使用本地緩存。
前端能做的醉大限度的緩存策略是:HTML 文件每次都向服務(wù)器詢問(wèn)是否有更新,JS/CSS/Image資源文件則不請(qǐng)求更新,直接使用本地緩存。那 JS/CSS 資源文件如何更新?常見(jiàn)做法是在在構(gòu)建過(guò)程中給每個(gè)資源文件一個(gè)版本號(hào)或hash值,若資源文件有更新,版本號(hào)和 hash 值變化,這個(gè)資源請(qǐng)求的 URL 就變化了,同時(shí)對(duì)應(yīng)的 HTML 頁(yè)面更新,變成請(qǐng)求新的資源URL,資源也就更新了。
json 數(shù)據(jù)的緩存可以用 localStorage 緩存請(qǐng)求下來(lái)的數(shù)據(jù),可以在受次顯示時(shí)先用本地?cái)?shù)據(jù),再請(qǐng)求更新,這都由前端 JS 控制。
這些緩存策略可以實(shí)現(xiàn) JS/CSS 等資源文件以及用戶數(shù)據(jù)的緩存的全緩存,可以做到每次都直接使用本地緩存數(shù)據(jù),不用等待網(wǎng)絡(luò)請(qǐng)求。但 HTML 文件的緩存做不到,對(duì)于 HTML 文件,如果把 Expires / max-age 時(shí)間設(shè)長(zhǎng)了,長(zhǎng)時(shí)間只使用本地緩存,那更新就不及時(shí),如果設(shè)短了,每次打開(kāi)頁(yè)面都要發(fā)網(wǎng)絡(luò)請(qǐng)求詢問(wèn)是否有更新,再確定是否使用本地資源,一般前端在這里的策略是每次都請(qǐng)求,這在弱網(wǎng)情況下用戶感受到的白屏?xí)r間仍然會(huì)很長(zhǎng)。所以 HTML 文件的“緩存”和跟“更新”間存在矛盾。