文章目錄
涉及原理
HTTP協議
三次握手
- 客戶端發出請求報文;
- 服務端收到後進行應答,對客戶端的連接請求進行確認;
- 客戶端收到服務器收到的連接確認請求後再向服務器發送確認信號。
四次揮手
- 數據傳輸結束後,客戶端向服務器發送斷開連接的請求;
- 服務器端收到確認報文後進行確認,釋放從客戶端到服務器端這個方向的連接,TCP連接處於半關閉狀態;
- 服務器向客戶端數據發送完了之後,服務器端向客戶端發送TCP釋放連接請求;
- 客戶端對服務器斷開請求進行響應,關閉從服務器端到客戶端的連接。
這裏爲什麼是斷開連接是四次呢,因爲TCP是全雙工通信機制,也就是雙向同時通信
從輸入URL到 頁面渲染完畢,發生了什麼
- 瀏覽器解析域名,將URL解析,獲得對於服務器的IP地址;
- 瀏覽器與遠程服務器通過TCP三次握手建立連接連接(TCP三次握手);
- 建立連接後瀏覽器會通過HTTP GET請求頁面資源
- 遠程服務器收到請求,會做邏輯操作,查找數據庫,讀取文件,將資源並通過http響應返回資源;
- 瀏覽器開始下載頁面資源,瀏覽器對返回HTML資源進行解析渲染;
- 瀏覽器會將HTML解析生成DOM tree,將css解析生成CSSOM,將DOM tree和Css tree合併生成render tree(:after和:before這樣的僞元素會在這個環節被構建到DOM樹中)
- 頁面根據生成的Render Tree對元素進行大小、位置計算,繪製到屏幕上
- 加載script的js文件,執行js
瀏覽器渲染機制
- 解析文件,HTML構建DOM樹
- 將css文檔,構建CSSOM樹
- 將DOM樹和CSSOM樹合成Render Tree
- 計算元素大小、位置,繪製到頁面上
資源加載執行順序
- 瀏覽器加載HTML頁面是邊下載邊解析,解析順序是自上而下的;
- 解析過程中發現css文件會並行進行加載,
- JS: 解析過過程中發現<script>標籤會暫停解析(這裏JS引入方式不包括async和defer),先加載js文件並執行後再繼續解析HTML文檔(因爲JS可以修改DOM樹,這裏(JS的加載和執行)會阻塞HTML頁面的解析從而避免DOM渲染衝突)
- CSS: 文檔解析的時候遇到css資源會下載樣式文件,不會阻塞DOM的解析;
css文件放於文檔頭部,js文件放於文檔底部,可以讓頁面修改快速下載資源且渲染頁面,並且避免JS執行時DOM節點還沒渲染到頁面會出現執行錯誤
重繪、重排
- 重繪(repaint):當元素節點的樣式發生改變,但位置及大小不改變,比如改變字體顏色、背景等,對頁面其他節點不造成影響,這時候會觸發瀏覽器重繪;
- 重排(reflow):當元素節點發生大小、位置發生變化,對其他節點位置造成影響,這時候佈局發生改變,會觸發瀏覽器重排。
重排會引起重繪,重繪不一定會引起重排(重排較重繪會消耗更多的性能)。
一、文件資源加載優化
1、減少少加載文件數量和體積
- 代碼(html、js、css)打包壓縮
- 刪除冗餘代碼:webpack生產環境使用tree-shaking
- 圖片小圖合併成雪碧圖、使用合適的圖片類型(jpg、png、svg)
- 使用gzip壓縮內容:服務器設置accept-enconding:gzip 開啓gzip
2、緩存
本地存儲
- cookie
cookie可以緩存用戶認證的標誌,設置在某個時間內有效可以不需要多次認證。
cookie的體積限定,會爲該作用域名下所有請求都帶上所有當前域名的cookie從而造成性能浪費; - 靜態資源緩存
響應頭使用Expires或Cache-Control進行強緩存
響應問使用協商緩存頭if-modified-since或etag - 使用webStroage緩存數據
webStroage的localStroage和sessionStroage存儲量大,不自動發送給服務端,js可以操作 - indexdDB運行在瀏覽器上的非關係型數據庫
indexdDB是一個key-value型的事務模式的數據庫;
可以在在線和離線的時候使用,遵從同源協議,所以只能訪問同域中存儲的數據,而不能訪問其他域的;
可以在瀏覽器端進行數據持久化,可以保存大量數據,在離線的時候也可以訪問; - PWA 基於存儲技術的應用模型
可以Service worker在後頭利用緩存快速加載頁面,消除對網絡的依賴;
可以通過App Mainfest實現PWA的安裝,將頁面添加至手機屏幕上;
可以通過Service worker實現消息推送
通過Service Worker + HTTPS + Cache API + indexedDB實現離線加載和緩存
服務器緩存
比如CDN、Nginx、Apache
2、使用CDN減少用戶與服務器的距離
CDN是內容分發網絡,CDN服務器可以返回最近的緩存服務器給用戶,從而減短下載的鏈路距離從而加快下載速度。同時可以緩存靜態文件。
3、按需加載、懶加載、預加載
-
按需加載
在引入組件時可以只引入自己需要的的組件,避免不需要用到的代碼造成內容過多影響下載速度;
如果是首頁只引入首頁首次加載所必需的的資源,其他可以使用異步的方式稍後加載; -
懶加載
圖片或者其他非首屏需要展示的數據可以使用懶加載,避免加載數據過多阻塞頁面操作; -
預加載
prefetch: 在加載的資源連接加上dns-prefetch標籤,告訴客戶端未來可能會用到的資源,瀏覽器可以今早解析DNS;
<link rel="dns-prefetch" href="//img.alicdn.com" />
preconnect: 瀏覽器會提前解析DNS,還會建立tcp連接;
<link rel="preconnect"href="http://css-tricks.com">
prefetch: 確認某些資源未來一定會用到,告訴瀏覽器提前請求並緩存好資源。可預拉去圖片、腳本、或者其他可以被緩存的資源。
<link rel="prefetch" href="need.css">
圖片預加載:var preloadImgList = [ 'images/1.jpg', 'images/2.jpg', 'images/3.jpg' ]; preloadImgList.forEach(function(v) { var img = new Image(); img.src = v; });
preload: 指明哪些資源是頁面加載完成後立即需要的,在瀏覽器的主渲染機制介入前就進行預加載。(常用於加載CSS文件)
//預加載css文件 <link rel="stylesheet" href="styles/main.css">
// 預加載js,但是並不會執行它 var preloadLink = document.createElement("link"); preloadLink.href = "myscript.js"; preloadLink.rel = "preload"; preloadLink.as = "script"; document.head.appendChild(preloadLink); // 需要執行 var preloadedScript = document.createElement("script"); preloadedScript.src = "myscript.js"; document.body.appendChild(preloadedScript);
prefetch 意圖是預獲取一些資源,以備下一個導航/頁面使用(比如,當你去到下一個頁面時),但是對當前頁面沒有什麼助益;瀏覽器會給prefetch的資源一個比較低的優先級;
preload 的資源優先級會比較高(畢竟當前頁面比較重要),更符合當前頁面的優化需求和預期;**
二、代碼層面優化
- css文件放在文檔頭部,js文件放於頁面底部;
- 精簡代碼,去掉冗餘代碼
- 減少DOM操作
動態插入DOM時可以先把要插入DOM節點緩存起來,一次性插入,避免多次操作DOM導致頁面多次渲染性能消耗;
修改樣式的時候可以使用class的方式; - 節流、防抖:對於連續的事件進行優化,避免連續觸發造成不必要的性能損耗或頁面卡頓;