基於網上的大量參考資料,梳理對這一加載流程的理解。深知本身的認知理解有限,請你們多多拍磚。javascript
這一過程的瀏覽器行爲表象( 步驟分解 ):css
瀏覽器主線程解析URL、經過服務器地址查找具體IP地址( DNS解析 )html
DNS的解析過程:前端
注:java
- 起初互聯網信息中心是總體管理一份hosts文件,因爲網絡規模不斷擴大不得不產生一個能夠有效管理主機名和ip地址之間對應關係的系統(NDS系統) - DNS就是互聯網中的分佈式數據庫
- 咱們根據dns解析原理去優化dns加載速度 預加載DNS:
<link rel="dns-prefetch" href="/img.alicdn.com">
瀏覽器是經過HTTP發起的請求,而HTTP屬於TCP/IP協議族的子級,TCP/IP協議族裏最重要的一點就是分層(五層)webpack
- 應用層:解析成IP地址併發送HTTP請求( NDS和HTTP屬於應用層 )
- 傳輸層:三次握手創建TCP鏈接( 爲應用層提供 - 靠譜的分片數據傳輸 )
- 網絡層:IP尋址( 爲傳輸層提供傳輸路線 )( 在與服務器之間經過多臺計算機和網絡設備進行傳輸時,網絡層起的做用就是在衆多的選項內選擇一條傳輸路線 )
- 鏈路層:網卡
- 物理層:物理傳輸 ( 硬件範疇比特流、雙絞線、電磁波 .. )
TCP負責創建鏈接、發送數據以及斷開鏈接。TCP提供將應用層發來的數據順利發送至服務端的可靠傳輸,爲了實現這一目的,須要在應用層數據前端附加一個頭TCP首部( 源端口號和目標端口號、序號、校驗 ),以後傳遞給IP層,IP層負責提供傳輸路線git
web開發者必須熟悉http。也就是先後端的http交互 ( http報文結構、緩存、跨域、cookie、安全...) 。 http是依託於TCP的,所以...github
TCP協議採用了三次握手策略( 確保雙方均可以收到 )。TCP連接是全雙工的,雙方的數據讀寫能夠經過一個鏈接進行。web
形象一點的描述:ajax
// 客戶端(毛蛋):二狗二狗,我是毛蛋,我是毛蛋,聽到請回答,聽到請回答!
// 服務端(二狗):二狗收到,二狗收到,毛蛋請講,毛蛋請講,完畢!
// 客戶端(毛蛋):毛蛋收到, ...
複製代碼
四次揮手:保證雙發數據都發送完畢,都認爲能夠斷開。若是客戶端發送關閉請求時,服務端沒有須要傳遞給客戶端的信息時,此時能夠合併爲一條數據發送會客戶端。
// 客戶端(第一次揮手):主動發起關閉請求(FIN報文段),客戶端此時進入FIN_WAIT_1狀態
// 服務端(第二次揮手):回覆客戶端(設置ACK報文段),服務端進入CLOSE_WAIT狀態,客戶端收到ACK報文後,進入FIN_WAIT_2狀態
// 服務端(第三次揮手):服務器此時會觀察本身是否還有數據沒有發送給客戶端,有,先發送數據再發送FIN報文,沒有,則直接發送FIN報文給客戶端,同時服務端進入LAST_ACK狀態
// 客戶端(第四次揮手):客戶端收到服務端的FIN報文段,向服務器發送ACK報文,而後客戶端進入TIME_WAIT狀態,服務端收到客戶端的ACK報文段後,就關閉鏈接;此時,客戶端等待2MSL後依然沒有收到服務端的回覆,則證實服務端已正常關閉,客戶端也能夠關閉這個鏈接了
複製代碼
注:
- 客戶端最後爲何須要等待態( TIME_WAIT )?傳遞的 FIN 報文段有可能會丟失
- 何時進行四次揮手:根據
Connection
請求頭,若是是Keep-alive
,服務器就保持TCP
連接,若是沒有Keep-alive
或者主動 close ,則服務器 Response 傳輸完成後主動關閉TCP
連接 ( http1.1 默認開啓 Keep-alive 的,在瀏覽器tab關閉時,TCP
連接才關閉 )
瀏覽器經過(HTTP-TCP-IP-鏈路-物理),到達服務器,服務器在經過協議進行一步步(層鏈路-IP-TCP-HTTP)反向解析,拿到HTTP信息後 - 服務端進行處理( 反向代理、安全攔截、跨域驗證、業務邏輯... ),等待程序執行完畢後,再通過層層封裝發送給前端,完成交互
兩種類型:強緩存(200 from cache)與協商緩存(304)
- 強緩存http1.1(Cache-Control/Max-Age)、http1.0(Pragma/Expires)
- 協商緩存http1.1(If-None-Match/E-tag)、http1.0(If-Modified-Since/Last-Modified) http1.1的方法老是優與http1.0,主流的方案緩存這四種方案老是會都加上 更好的方案是消滅304,除了主頁以外都是強緩存,須要更新時修改靜態資源的MD5戳便可 http資源緩存
瀏覽器拿到HTML文檔,
- DOM解析(標記化和樹構建) - DOM樹
- CSSS解析 - CSSOM樹
- 將DOM樹和CSSOM樹合併刪除渲染樹(Render Tree) - 其實能夠把根html看作是一個層提高(就像總體的javascript自己就是一個宏任務同樣) - Paint
- 層疊上下文處理 - 造成Layer Tree:把渲染樹中的一些節點生成單獨的一層( 層提高 ) - Paint
- 層合併處理 - 造成Graphics Lyaer(GPU硬件加速) - GPU直接繪製
- 附1:HTML沒法用常規的自上而下或者自下而上的進行解析,由於瀏覽器從來對一些無效的HTML用法採用包容態度,解析過程須要不斷循環往復。源內容在解析過程當中一般不會改變,可是在結構中JS每每會添加額外的標記(重排 || 迴流)。
- 附2:標記化:詞法分析(起始標記、結束標記、屬性名、屬性值)。構建樹:標記生成後,傳遞給構件樹,標記一個構建一個,如此反覆
- 附3:CSS解析與DOM解析同步進行(DOM解析結構,CSS解析樣式,二者並不衝突)
- 附4:默認DOM和CSS加載與JS互斥(JS中可能會訪問咱們CSS中的樣式 && 結構)
- 附5:生成Graphics Lyaer的元素(video、canvas、flash、CSS3D、perspective(透視)、opacity,transfrome應用了animation、transition時...)
不可避免的在頭部或者body中間加載JS文件, defer異步加載JS - 在DOM解析完後當即執行( 效果等同在body底部,主入口文件有一個便可 ),async異步加載JS - 在JS加載完後當即執行(建議獨立的代碼使用,如:baidu統計).
個人CSS代碼中歷來沒有怎麼寫過,形成額外的請求,若是真的想用,使用sass,會自動合併(引入佔位符不會形成代碼重複)
a標籤空href,會重定向到當前頁面地址 Form給空method,會提交表單到當前頁面地址
<link rel="dns-prefetch" href="/img.alicdn.com">
let CacheEl = {
container: document.querySelectorAll('.container'),// 只有querySelectorAll返回的NodeList爲靜態的
divCollection: document.getElementsByTagName('div),
// HTMLCollection爲動態
$Box: $('#box')
};
複製代碼
- 拼接完成後,再innerHTML更新DOM
- DocumentFragment對象實際上理論中能作到優化,可是
- 第二中方案比第一種方案時間要長,由於現代瀏覽器能優化的最終都會被瀏覽器優化
修改和訪問DOM分開批量進行(讀取DOM會觸發瀏覽器一次渲染)
其實DOM操做時代,最熟悉就是事件代理了(能動態捕獲添加的節點)
生命週期的概念:不用時清除定時器、不用時清除事件監聽器、建立最小做用域(GC)、清除對象引用
細碎點不少,有機會再繼續 (⊙﹏⊙)b (⊙﹏⊙)b (⊙﹏⊙)b
附:這篇博客 也許 想表達 恩,也許就是一篇博客 (⊙﹏⊙)b