轉自---> 前端食堂
這是一道十分常見的面試題
流程
1、用戶在地址欄輸入內容后,地址欄會將輸入的內容進行合成 URL。
2、當用戶輸入完內容并按下回車鍵時,瀏覽器會在當前頁面執行 beforeunload 事件,你可以在這個鉤子中詢問是否要離開當前頁面,常見于一些表單提交的場景。
3、接下來開始導航流程,瀏覽器進入加載狀態。
4、瀏覽器的網絡進程會先查找緩存中是否存在該資源,有的話直接返回,如果沒有的話會發起 URL 請求。
: 瀏覽器獲取了這個url,當然就去解析了,它先去緩存當中看看有沒有,從 瀏覽器緩存-系統緩存-路由器緩存 當中查看,如果有從緩存當中顯示頁面,然后沒有那就進行步驟5;
緩存就是把你之前訪問的web資源,比如一些js,css,圖片什么的保存在你本機的內存或者磁盤當中。
在chrome瀏覽器中輸入網址: chrome://chrome-urls/ chrome-urls是一個看到所有的Chrome支持的偽RUL,找到其中的chrome://appcache-internals/ 可以看見chrome的本地緩存地址:Instances in: C:\Users\User\AppData\Local\Google\Chrome\User Data\Default (0)5、接下來首先要進行的是 DNS 解析,獲得請求域名的服務器的 IP 地址(這個過程我也畫了一張圖,放在下文),如果協議是 HTTPS,還需要建立 TLS 連接。
6、接著利用目標服務器的 IP 地址建立 TCP 連接(三次握手),構建 HTTP 請求報文,發起請求。服務器收到請求后,會根據請求信息生成響應報文。
7、瀏覽器的網絡進程接收到響應報文后進行解析,如果狀態碼是 301 或者 302(還有 300、303 等 3xx 的狀態碼),則需要取得響應頭中的 Location 對應的地址進行重定向,再重新發起請求。
8、如果狀態碼是 200,瀏覽器會根據響應頭中的 Content-Type 字段來識別返回的響應體數據類型,從而進行不同的流程。如 text/html 代表 html 格式, application/octet-stream 代表字節流類型,瀏覽器會按照下載類型來處理。
9、如果是 HTML,瀏覽器會遵循 process-per-site-instance 默認策略準備渲染進程,準備好后就提交文檔(將網絡進程接收到的數據提交給渲染進程)。文檔被提交后,渲染進程便開始進行頁面解析和子資源的加載。
process-per-site-instance 默認策略:每個標簽對應一個渲染進程,如果從一個頁面打開了一個新頁面,新打開的頁面與當前頁面還屬于同一個站點的話,那么新頁面會復用當前頁面的渲染進程。
瀏覽器的網絡進程會先查找緩存中是否存在該資源,有的話直接返回,如果沒有的話會發起 URL 請求
目前 Chrome 的瀏覽器包括如下進程:
- 1 個瀏覽器(Browser)主進程
- 1 個 GPU 進程
- 1 個網絡(NetWork)進程
- 多個渲染進程(運行在沙箱模式下)
- 多個插件進程
HTML渲染流程
在上圖中一并畫了出來,需要經過以下幾個階段:構建 DOM 樹--->樣式計算--->布局--->分層--->繪制--->分塊--->光柵化--->合成
DNS
DNS 的解析是一個遞歸流程,順序如下圖中數字標記所示:
- 根 DNS 服務器:返回頂級域 DNS 服務器的 IP 地址。
扯一句:世界上有13臺根服務器,而有N臺根鏡像服務器,所以有些國外地址會被墻 ~~~,說明域名解析第一步并不是走的根服務器,而是由根鏡像服務器控制住做了過濾,有選擇性地進行了域名解析,所以如果根域名服務器出了問題,我覺得我們國內仍然可以做到正常訪問,當然只是新更新的域名無法訪問。 - 頂級 DNS 服務器:返回權威 DNS 服務器的 IP 地址
- 權威 DNS 服務器:返回相應主機的 IP 地址
JS 棧 垃圾數據回收
- 示例代碼1:
function hello () {
let name = '數據'
}
hello()
console.log(name) // Uncaught ReferenceError: name is not defined 在執行上下文時,存放在棧內存中的name地址和數據【內存塊】已經回收掉了,所以在全局上下文中是訪問不到。
- 示例代碼2:
function hello () {
let name = '前端食堂'
let food = { name: '回鍋肉' }
function world () {
var description = { slogan: '吃好每一頓飯' }
}
world()
}
hello()
上面的代碼所對應的內存堆棧空間如下圖所示:
棧中的垃圾回收比較簡單,當一個函數執行結束后,JavaScript 引擎會通過向下移動 ESP 來銷毀函數調用棧中所保存的執行上下文,ESP 就是記錄當前執行狀態的指針。
- 垃圾回收操作會暫停 JavaScript 的運行,回收完畢后才會恢復執行,這種行為就是全停頓。
為了降低全停頓所帶來的卡頓,V8 引擎采用了增量標記(Incremental Marking) 算法進行優化,將標記過程分為一個個小任務,這些小任務的執行時間比較短,可以穿插在其他的 JavaScript 任務中間執行,這樣就不會有明顯的卡頓了。
當然,V8 所采用的優化方案不只這一種,而是多種方案綜合使用的,除了增量回收還有并行回收、并發回收等。
并行回收:垃圾回收器會使用多個輔助線程來并行執行垃圾回收
并發回收:回收線程在執行 JavaScript 的過程中,輔助線程在后臺執行垃圾回收
如果你了解【** React 的 Concurrent 模式中時間切片的原理 **】,它的實現思想是不是與增量標記算法有異曲同工之妙呢。