前端性能優化,是每個前端必備的技能,優化自己的代碼,使自己的網址可以更加快速的訪問打開,減少用戶等待,今天就會從幾個方面說起前端性能優化的方案,
看下面的一張圖,經常會被面試官問,從輸入URL到頁面加載完成,發生了什么?

1.用戶輸入www.baidu.com
2.瀏覽器通過DNS。吧url解析ip
3.和ip地址建立TCP連接,發送HTTP請求
4.服務器接收請求,查庫,讀文件等,拼接好 返回的HTTP響應
5.瀏覽器收到首屏html,開始渲染,
6.解析html位dom
7.解析css為css-tree
8.dom+css生成render-tree繪圖
9.加載script的js文件
10.執行js文件
DNS緩存
DNS是“域名系統”的縮寫,它的工作是將域名和主機名轉化為服務器主機的 IP 地址;
DNS查找流程:瀏覽器緩存 — 本地hosts文件 — 本地DNS解析器緩存 — 本地DNS服務器 — 本地DNS服務器設置(是否設置轉發器)— 根DNS服務器
瀏覽器緩存之客戶端緩存
無需請求的memory cache,disk cache;
需要發請求驗證的Etag、Last-Modified304;
H5新增的 localStorage、sessionStorage;
合理利用以上緩存,可以很大程度上提高前端性能。
網站存在緩存怎么解決?
1.文件加哈希
1.上線之后,要求用戶強刷新,這種問題,用文件名加指紋方式解決
2. a.hash.js hash是整個a.js文件的md5值,文件內容不變,hash不變,緩存生效
2.緩存文件怎么解決
1.加時間戳 <script src="/a.js?_t=xx">
2.加版本號 <script src="/a.js?_v=1.6"> 比如jq,vue公用庫,內容沒有改變 重新加載
3.加指紋 但是不產生新文件 <script src="/a.js?h=abcd12sa"> 不能清除Cdn緩存,但是生成新文件,會有問題(html,js那個先上)
4.最終,誕生最優的產生文件<script src="/a.abcd12sa.js">先上js,在上html webpack build 打包
優化策略
1.長連接
2.減少文件體積
1.js打包壓縮
1.無效字符的刪除、剔除注釋、代碼語義的縮減與優化、代碼保護
2.使用在線網站壓縮、使用 html-minifier 對html 中的 js 進行壓縮、使用uglifyjs2 對 js 進行壓縮
2.圖片壓縮
1.把網站上用到的一些圖片整合到一張單獨的圖片中
3.css壓縮
1.無效代碼刪除、css語義合並
2.使用在線網站壓縮、使用 html-minifier 對html 中的 css 進行壓縮、使用clean-css 對 css 進行壓縮
4.html 壓縮
1.壓縮在文本文件中有意義但是在HTML中不顯示的字符,包括空格、制表符、換行符、注釋等
2.使用在線網站壓縮、nodejs提供了html-minifier 工具、后端模板引擎渲染壓縮
5.開啟 gzip
6.文件合並
1.如果不合並 === > 文件與文件之間有插入的上行請求,增加了N - 1 個網絡延遲;受丟包問題影響更嚴重;經過代理服務器時可能會被斷開
2.如果合並 === > 首屏渲染時間變長; 文件緩存大面積失效
3.公共庫合並、不同頁面的合並
4.使用在線網站進行文件合並、使用 nodejs 實現文件合並
3.減少文件請求次數
1.雪碧圖
2.js,css打包
3.緩存控制
4.懶加載
4.減少用戶和服務器的距離
(地理位置)
1.cdn js可以推到cdn緩存上
5.本地存儲
6.圖片大小計算
對於一張 100
100 像素的圖片來說,圖像上有 10000 個像素點,如果每個像素的值是 RGBA 存儲的話,那么也就是說每個像素有 4 個通道,每個通道 1 個字節(8 位 = 1個字節),所以該圖片大小大概為 39KB(10000 * 4 / 1024)。但是在實際項目中,一張圖片可能並不需要使用那么多顏色去顯示,我們可以通過減少每個像素的調色板來相應縮小圖片的大小。
瀏覽器緩存機制
通過網絡獲取內容及速度緩存慢有開銷巨大,較大相應需要在客戶端與服務器之間進行多次往返通信,這回延遲瀏覽器獲得處理內容的時間,還會增加訪問者流量的費用,因此,緩存重復利用之前獲取的資源能力成為性能優化的一個關鍵方面
廣義的緩存,可以分為四個,大家對httpcache比較熟悉
1.Http Cache
2.Service Worker Cache
3.Memory Cache
4.Push Cache
Http Cache
瀏覽器大佬:需要獲取main.js,看下強緩存里有沒有
1.Expires和Cache-Control兩個header來控制強緩存
2.expires: Mon, 16 Mar 2020 09:50:27 GMT
3.last-modified: Thu, 15 Feb 2018 14:17:52 GMT
Memory Cache
內存緩存,短命,比如常用數據js里,瀏覽器也有自己的策略,base64圖片,體積小的靜態資源
Service Worker Cache
是一種獨立於主干線程之外的javascript線程,它脫離於瀏覽器窗體,算是幕后工作,可以實現離線緩存,網絡代理等
圖片優化
圖片通常是最占用流量的,pc端加載平均圖片大小是600k,簡直比js打包后的文件還大,所以針對圖片的優化,不同場景,使用不同文化的類型
1. jpg
1.有壓縮
2.體積小,不支持透明
3.用於背景圖,輪播圖
2.png
1.無壓縮,質量高,支持透明
2.色彩線條更豐富,小圖,比如logo,商品icon
3.svg
1.文本,體積小,矢量圖
2.渲染成本,學習成本
4.圖片打成雪碧圖,減少http請求次數
gzip
Http壓縮就是以縮小體積為目的,對HTTP內容進行重新編碼的過程
Gzip壓縮背后的原理,是在一個文本文件中找出一些重復出現的字符串,臨時替換他們,從而、使整個文件變小,根據這個原理,文件找那個代碼重復率越高,那么壓縮的效率越高,使用Gzip收益就越大,反之亦然基本來說Gzip都是服務器干的活,比如nginx
本地存儲
常見本地存儲格式有 cookie localstroage sessionStroage indexDB
1.cookie
最早,體積先定。性能浪費,所有請求都帶上所有的當前域名的。
因為 http 請求無狀態,所以需要 cookie 去維持客戶端狀態
cookie 生成方式:http response header 中的 set-cookie; js 中可以通過document.cookie讀寫cookie
使用:用於瀏覽器端和服務器端的交互;客戶端自身數據的存儲
過期時間:expire
存儲限制:作為瀏覽器存儲,大小4kb左右;需要設置過期時間 expire
cookie 存儲能力被 localstorage 代替
httponly 不允許 js 讀寫
cookie 中在相關域名下面 --- cdn的流量損耗 。 解決:cdn 的域名和主站的域名要分開
2.Web Storage
1.存儲量大,不自動發個服務器,js控制
2.localstroage
HTML5 設計出來專門用於瀏覽器存儲的
大小為 5M 左右
僅在客戶端使用,不和服務端進行通信
接口封裝較好
瀏覽器本地緩存方案
3.sessionStroage
會話級別的瀏覽器存儲
大小為 5M 左右
僅在客戶端使用,不和服務端進行通信
接口封裝較好
對於標表單信息的維護
3.indexDB
運行在瀏覽器上的非關系型數據庫
4.pwa
基於緩存技術的應用模型
可靠:在沒有網絡的環境中也能提供基本的頁面訪問
快速:針對網頁渲染及網絡數據訪問有較好的優化
融入:應用可以被增加到手機桌面,並且和普通應用一樣有全屏、推送等特性
重繪與回流
回流:當我們對DOM修改引發了DOM幾何尺寸的變化(比如修改元素的寬,高度或者隱藏元素等)時,瀏覽器需要重新計算元素的幾何屬性,(其他元素的幾何屬性和位置也會因此受到影響),然后再將計算的結果繪制出來,這個過程就是回流(也加重排)
重繪:當我們對DOM的修改導致了樣式的變化,卻並未影響幾何屬性,(比如修改了顏色和背景色)時,瀏覽器不需要重新計算元素的幾何屬性,直接為該元素繪制新的樣式,(跳過了上圖所示的回流環節)。這個過程叫做重繪
由此我們可以看出,重繪不一定導致回流,回流一定導致重繪
回流是影響最大的
1.窗體,字體大小
2.增加樣式表
3.內容變化
4.class屬性
5.offserWidth和offsetHeight
6.fixed
節流和防抖
節流
預定一個函數只有在大於等於執行周期時才執行,周期內調用不執行
// 函數節流 每隔多少時間執行一次
const throttle = (func ,wait = 100) =>{
// 無論調用多少次,函數都是100毫秒執行一次
let lastTime =0;
return(...args) =>{
let now = new Date().getTime()
if(now - lastTime >wait) {
func.apply(this.args)
lastTime = now
}
}
}
let i =1;
window.addEventListener('scroll',throttle(()=>{
// 使用做圖片懶加載
console.log(i)
i+=1
},350))
防抖
在函數需要頻繁觸發時,只有當有足夠空閑的時間時,才執行一次
/*
校驗用戶是不是重復,用戶輸入完,向后端發送請求
如果用戶每次輸入,都發生請求,造成請求過多
用戶停止輸入字符串350毫秒,在發出
*/
const debounce = (func,wait = 350) =>{
let timer =0;
return (...args)=>{
if(timer) {
clearInterval(timer)
}
timer = setTimeout(() => {
func.apply(this,args)
}, wait);
}
}
let i =1;
window.addEventListener('scroll',debounce(()=>{
// 驗證
console.log(i)
i+=1
},350))
lazy-load
對於一些圖片多,頁面長的網頁來說,如果每次打開頁面加載全部的網頁內容,頁面加載速度勢必會受到影響,如果每次打開網頁只將網頁可視區域的內容加載給用戶 ,將大大提高網頁瀏覽速度,同時也減輕服務器負載,我們可以使用lazyload.js來實現對圖片的延遲加載,當網頁圖片進入到瀏覽器可視區域時,才會去請求服務器加載圖片。
// 獲取所有的圖片
const img = document.getElementsByTagName('img')
// 獲取可視區域的高度
const viewHeight = window.innerHeight || document.documentElement.clientHeight;
// num用於計算當前顯示到那一張圖片,避免每次都是從第一張開始檢查是否漏出
let num =0;
function lazyload() {
for(let i=num;i<img.length;i++) {
// 用可是區域高度減去元素頂部距離可視區域頂部的高度
let distance = viewHeight - img[i].getBoundingClientRect().top
// 如果可視區域高度大於等於元素頂部距離可視區域頂部的高度,說明元素露出
if(distance >=0) {
// 給元素寫入真實的src,展示圖片
img[i].src = img[i].getAttribute('data-src')
// 前i張圖片已經加載完畢,,下次從第i+1張開始檢查是否露出
num = i+1
}
}
}
// 監聽scroll
window.addEventListener('scroll',lazyload,false)
performance.getEntriesByType('navigation') 性能檢測
通過在瀏覽器控制台輸入這個命令,就可以檢測到網頁加載數據,檢測網頁加載性能

列入:
DNS查詢耗時 通過使用domainLookupEnd - domainLookupStart 就等於dns查詢的時間
TCP鏈接耗時 通過 connectEnd - connectStart
HTTP請求耗時 通過 responseEnd - responseStart
解析dom樹耗時 通過 domComplete - domInteractive
白屏時間 通過 responseStart - navigationStart
DOMready時間 通過 domContentLoadedEventEnd - navigationStart
onload時間 通過 loadEventEnd - navigationStart 也即是onload回調函數執行的時間
Lighthouse分析web應用程序和web頁面,收集關於開發人員最佳實踐的現代性能指標和見解,讓開發人員根據生成的評估頁面,來進行網站優化和完善,提高用戶體驗。
1.可以在谷歌商店安裝一個Lighthouse一個插件就可以了,下面我是檢測github網站的數據
2.使用node全局安裝
npm install -g lighthouse
安裝完之后運行,也是找的github網址,運行成功之后,會彈出一個生成的html頁面。

生成一個html文件,找到然后直接打開就行


瀏覽器渲染

1.在這一步瀏覽器執行了所有的加載解析邏輯,在解析HTML的過程中發出了頁面渲染所需要的各種外部資源請求
2.瀏覽器將識別並加載所有的css樣式信息與dom樹合並,最終勝出頁面render樹,(:after :brfore這樣的偽元素在這個環節被構建到DOM樹中)
3.頁面中所有元素相對位置信息,大小等信息均在這一步得到計算
4.在這一步瀏覽器會根據我們的DOM代碼結果,把每一個頁面圖層轉換為像素,並對所有的媒體文件進行解碼
5.最后一步瀏覽器會合並各個圖層,講數據有CPU輸給GPU最終繪制在屏幕上,(復雜的視圖會給這個階段GPU計算帶來一些壓力,在實際中是為了優化動畫性能,我們有時候會手動區分各個視圖)
渲染過程說白了,首先是基於HTML構建一個DOM樹,這顆DOM樹與css解析器解析除的CSSOM相結合,就有了布局渲染樹,最后瀏覽器以布局渲染樹為藍本,去計算布局並繪制圖像,我們頁面初次渲染就大功告成了。
之后每當一個新元素加入到這個DOM樹中,瀏覽器便會通過css引擎查遍css樣式表,找到符合該元素的樣式應用到這個元素上,然后在重新去繪制他
服務端渲染 等等.....
以上就是所總結的常見的前端性能優化,如有不足,希望大佬多多指點指點