<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          圖解瀏覽器,解釋瀏覽器那些不為人知的小秘密

          共 5379字,需瀏覽 11分鐘

           ·

          2021-01-26 11:17



          美味值:??????????

          口味:仔梅燒小排

          本文同步視頻版

          01 瀏覽器架構(gòu)演進(jìn)

          開(kāi)篇我們先來(lái)簡(jiǎn)單回顧下歷史,從 1993 年發(fā)布的第一款“好用”的瀏覽器 Mosaic,到 1994 年網(wǎng)景公司推出的紅極一時(shí)的 Navigator 瀏覽器,圖形用戶界面化的瀏覽器終于開(kāi)始推動(dòng)了 Web 技術(shù)的普及和發(fā)展。

          微軟也隨后推出了 IE,加入戰(zhàn)場(chǎng)并取得瀏覽器大戰(zhàn)“一戰(zhàn)”的勝利。戰(zhàn)敗的網(wǎng)景公司索性將 Navigator 源代碼開(kāi)源,創(chuàng)建了 Mozilla 基金會(huì),并于 2004 年發(fā)布了 Firefox 瀏覽器。

          蘋果公司于 2003 年發(fā)布了 Safari 瀏覽器,Google 公司于 2008 年發(fā)布了 Chrome 瀏覽器。Chrome 瀏覽器在瀏覽器大戰(zhàn)的“二戰(zhàn)”中技?jí)喝盒?,拔得頭籌?,F(xiàn)如今也是前端工程師最喜愛(ài)的瀏覽器,沒(méi)有之一。

          Chrome 瀏覽器從 2007 年以前的單進(jìn)程架構(gòu)到現(xiàn)在的多進(jìn)程架構(gòu),瀏覽器的架構(gòu)在不斷的升級(jí),變得更加穩(wěn)定、更加流暢、更加安全。目前 Chrome 的瀏覽器包括如下進(jìn)程:

          • 1 個(gè)瀏覽器(Browser)主進(jìn)程
          • 1 個(gè) GPU 進(jìn)程
          • 1 個(gè)網(wǎng)絡(luò)(NetWork)進(jìn)程
          • 多個(gè)渲染進(jìn)程(運(yùn)行在沙箱模式下)
          • 多個(gè)插件進(jìn)程

          不過(guò),軟件工程可沒(méi)有銀彈。瀏覽器的架構(gòu)體系也隨著調(diào)整變得更加復(fù)雜,也會(huì)有更高的資源占用。

          那么如何尋求一種在資源占用復(fù)雜架構(gòu)體系之間的平衡便成為了一個(gè)難題。

          小孩子才做選擇,魚和熊掌我都要!

          Chrome 團(tuán)隊(duì)在 2016 年使用“面向服務(wù)的架構(gòu)”(Services Oriented Architecture,簡(jiǎn)稱 SOA)的思想設(shè)計(jì)了新的 Chrome 架構(gòu)。

          他們將模塊重構(gòu)成獨(dú)立的服務(wù)(Service),服務(wù)運(yùn)行在獨(dú)立的進(jìn)程中,想要訪問(wèn)的話必須使用定義好的接口,通過(guò) IPC 來(lái)進(jìn)行通信。這樣的架構(gòu)無(wú)疑更加內(nèi)聚、松耦合、易于維護(hù)和擴(kuò)展。

          02 瀏覽器導(dǎo)航渲染流程

          從輸入 URL 到頁(yè)面展示,這中間發(fā)生了什么?

          這是一道十分常見(jiàn)的面試題,不過(guò)大多數(shù)人回答這個(gè)問(wèn)題時(shí)都不夠系統(tǒng)和全面,可見(jiàn)這道題能夠充分考察應(yīng)試者的知識(shí)深度。

          我畫了一張圖整理了瀏覽器的導(dǎo)航渲染流程,下面我們來(lái)一起查缺補(bǔ)漏。

          導(dǎo)航流程

          1. 用戶在地址欄輸入內(nèi)容后,地址欄會(huì)將輸入的內(nèi)容進(jìn)行合成 URL。
          2. 當(dāng)用戶輸入完內(nèi)容并按下回車鍵時(shí),瀏覽器會(huì)在當(dāng)前頁(yè)面執(zhí)行 beforeunload 事件,你可以在這個(gè)鉤子中詢問(wèn)是否要離開(kāi)當(dāng)前頁(yè)面,常見(jiàn)于一些表單提交的場(chǎng)景。
          3. 接下來(lái)開(kāi)始導(dǎo)航流程,瀏覽器進(jìn)入加載狀態(tài)。
          4. 瀏覽器的網(wǎng)絡(luò)進(jìn)程會(huì)先查找緩存中是否存在該資源,有的話直接返回,如果沒(méi)有的話會(huì)發(fā)起 URL 請(qǐng)求。
          5. 接下來(lái)首先要進(jìn)行的是 DNS 解析,獲得請(qǐng)求域名的服務(wù)器的 IP 地址(這個(gè)過(guò)程我也畫了一張圖,放在下文),如果協(xié)議是 HTTPS,還需要建立 TLS 連接。
          6. 接著利用目標(biāo)服務(wù)器的 IP 地址建立 TCP 連接(三次握手),構(gòu)建 HTTP 請(qǐng)求報(bào)文,發(fā)起請(qǐng)求。服務(wù)器收到請(qǐng)求后,會(huì)根據(jù)請(qǐng)求信息生成響應(yīng)報(bào)文。
          7. 瀏覽器的網(wǎng)絡(luò)進(jìn)程接收到響應(yīng)報(bào)文后進(jìn)行解析,如果狀態(tài)碼是 301 或者 302,則需要取得響應(yīng)頭中的 Location 對(duì)應(yīng)的地址進(jìn)行重定向,再重新發(fā)起請(qǐng)求。
          8. 如果狀態(tài)碼是 200,瀏覽器會(huì)根據(jù)響應(yīng)頭中的 Content-Type 字段來(lái)識(shí)別返回的響應(yīng)體數(shù)據(jù)類型,從而進(jìn)行不同的流程。如 text/html 代表 html 格式, application/octet-stream 代表字節(jié)流類型,瀏覽器會(huì)按照下載類型來(lái)處理。
          9. 如果是 HTML,瀏覽器會(huì)遵循 process-per-site-instance 默認(rèn)策略準(zhǔn)備渲染進(jìn)程,準(zhǔn)備好后就提交文檔(將網(wǎng)絡(luò)進(jìn)程接收到的數(shù)據(jù)提交給渲染進(jìn)程)。文檔被提交后,渲染進(jìn)程便開(kāi)始進(jìn)行頁(yè)面解析和子資源的加載。

          (當(dāng)然在第 7 點(diǎn)中還有 300、303 等 3xx 的狀態(tài)碼,具體含義可以參考我的這一篇專欄 那些年與面試官交手過(guò)的HTTP問(wèn)題)

          process-per-site-instance 默認(rèn)策略:每個(gè)標(biāo)簽對(duì)應(yīng)一個(gè)渲染進(jìn)程,如果從一個(gè)頁(yè)面打開(kāi)了一個(gè)新頁(yè)面,新打開(kāi)的頁(yè)面與當(dāng)前頁(yè)面還屬于同一個(gè)站點(diǎn)的話,那么新頁(yè)面會(huì)復(fù)用當(dāng)前頁(yè)面的渲染進(jìn)程。

          渲染流程

          渲染流程在上圖中一并畫了出來(lái),需要經(jīng)過(guò)以下幾個(gè)階段:

          1. 構(gòu)建 DOM 樹(shù)
          2. 樣式計(jì)算
          3. 布局
          4. 分層
          5. 繪制
          6. 分塊
          7. 光柵化
          8. 合成

          因?yàn)殇秩玖鞒痰膬?nèi)容比較多,本文先不詳細(xì)展開(kāi),后面我們?cè)匍_(kāi)一篇專欄進(jìn)行講解。

          DNS

          DNS 的解析是一個(gè)遞歸流程,順序如下圖中數(shù)字標(biāo)記所示:

          • 根 DNS 服務(wù)器:返回頂級(jí)域 DNS 服務(wù)器的 IP 地址
          • 頂級(jí) DNS 服務(wù)器:返回權(quán)威 DNS 服務(wù)器的 IP 地址
          • 權(quán)威 DNS 服務(wù)器:返回相應(yīng)主機(jī)的 IP 地址

          03 垃圾回收

          棧中的垃圾數(shù)據(jù)

          先來(lái)看一段簡(jiǎn)單的示例代碼:

          function?hello?()?{
          ????var?name?=?'前端食堂'
          ????var?food?=?{?name:?'回鍋肉'?}?
          ????function?world?()?{
          ????????var?description?=?{?slogan:?'吃好每一頓飯'?}
          ????}
          ????world()
          }
          hello()

          上面的代碼所對(duì)應(yīng)的內(nèi)存堆??臻g如下圖所示:

          棧中的垃圾回收比較簡(jiǎn)單,當(dāng)一個(gè)函數(shù)執(zhí)行結(jié)束后,JavaScript 引擎會(huì)通過(guò)向下移動(dòng) ESP 來(lái)銷毀函數(shù)調(diào)用棧中所保存的執(zhí)行上下文,ESP 就是記錄當(dāng)前執(zhí)行狀態(tài)的指針。

          堆中的垃圾數(shù)據(jù)

          先來(lái)看兩個(gè)概念,能夠幫助我們更好的理解堆中的垃圾回收操作。

          代際假說(shuō)

          堆中的垃圾回收策略都是建立在代際假說(shuō)的基礎(chǔ)之上,代際假說(shuō)有以下兩個(gè)特點(diǎn):

          1. 大部分對(duì)象在內(nèi)存中存在的時(shí)間很短,簡(jiǎn)單來(lái)說(shuō),就是很多對(duì)象一經(jīng)分配內(nèi)存,很快就變得不可訪問(wèn)。
          2. 不死的對(duì)象,會(huì)活得更久。

          分代收集

          在 Chrome 瀏覽器引擎 V8 中會(huì)把堆分為新生代老生代兩個(gè)區(qū)域,如下圖所示:

          顧名思義,生存時(shí)間短的對(duì)象放在新生區(qū)中,生存時(shí)間久的對(duì)象放在老生區(qū)中。

          堆中的垃圾回收需要用到垃圾回收器,分為主垃圾回收器副垃圾回收器。

          副垃圾回收器

          負(fù)責(zé)新生區(qū)的垃圾回收,新生區(qū)區(qū)域不大(為了執(zhí)行效率),回收頻繁。

          新生區(qū)中使用了 Scavenge 算法,該算法會(huì)把新生區(qū)的空間劃分為兩個(gè)區(qū)域,一半是對(duì)象區(qū)域,一半是空閑區(qū)域。

          副垃圾回收器的工作流程如下:

          1. 首先對(duì)對(duì)象區(qū)域中的垃圾進(jìn)行標(biāo)記。
          2. 標(biāo)記完成后,副垃圾回收器會(huì)將存活的對(duì)象復(fù)制到空閑區(qū)域中,為了避免產(chǎn)生內(nèi)存碎片,還需要進(jìn)行有序的排列,有序排列相當(dāng)于內(nèi)存整理。
          3. 完成復(fù)制后,將對(duì)象區(qū)域和空閑區(qū)域進(jìn)行翻轉(zhuǎn),就完成了垃圾回收的操作。

          翻轉(zhuǎn)的這種操作可以讓對(duì)象區(qū)和空閑區(qū)無(wú)限重復(fù)的使用,不過(guò)由于新生區(qū)空間并不大,很容易會(huì)被存活的對(duì)象塞滿。所以 V8 引擎采用了對(duì)象晉升的策略,經(jīng)過(guò)兩次垃圾回收后依然還能存活的對(duì)象會(huì)被晉升到老生區(qū)中。

          主垃圾回收器

          負(fù)責(zé)老生區(qū)中的垃圾回收,老生區(qū)中對(duì)象占用空間大,對(duì)象存活時(shí)間長(zhǎng)。

          除了上文說(shuō)到的新生區(qū)中晉升的對(duì)象,一些大的對(duì)象也會(huì)直接被分配到老生區(qū)。

          主垃圾回收器是使用了標(biāo)記 - 清除(Mark-Sweep)的算法,工作流程如下:

          1. 首先是標(biāo)記階段,從一組根元素開(kāi)始遞歸遍歷,能到達(dá)的元素就是活動(dòng)對(duì)象,否則就是垃圾。
          2. 然后使用標(biāo)記 - 清除算法進(jìn)行垃圾回收,不過(guò)回收后會(huì)產(chǎn)生大量不連續(xù)的內(nèi)存碎片。
          3. 于是又產(chǎn)生了另外一種算法標(biāo)記 - 整理(Mark-Compact),整理時(shí)可以讓存活的對(duì)象都向一端移動(dòng),然后直接清除掉端邊界以外的內(nèi)存。

          全停頓

          垃圾回收操作會(huì)暫停 JavaScript 的運(yùn)行,回收完畢后才會(huì)恢復(fù)執(zhí)行,這種行為就是全停頓。

          為了降低全停頓所帶來(lái)的卡頓,V8 引擎采用了增量標(biāo)記(Incremental Marking) 算法進(jìn)行優(yōu)化,將標(biāo)記過(guò)程分為一個(gè)個(gè)小任務(wù),這些小任務(wù)的執(zhí)行時(shí)間比較短,可以穿插在其他的 JavaScript 任務(wù)中間執(zhí)行,這樣就不會(huì)有明顯的卡頓了。

          當(dāng)然,V8 所采用的優(yōu)化方案不只這一種,而是多種方案綜合使用的,除了增量回收還有并行回收、并發(fā)回收等。

          • 并行回收:垃圾回收器會(huì)使用多個(gè)輔助線程來(lái)并行執(zhí)行垃圾回收
          • 并發(fā)回收:回收線程在執(zhí)行 JavaScript 的過(guò)程中,輔助線程在后臺(tái)執(zhí)行垃圾回收

          如果你了解 React 的 Concurrent 模式中時(shí)間切片的原理,它的實(shí)現(xiàn)思想是不是與增量標(biāo)記算法有異曲同工之妙呢。

          04 核心網(wǎng)頁(yè)指標(biāo) Core Web Vitals

          Google 大佬推出了 Core Web Vitals:目的是為了更好的簡(jiǎn)化場(chǎng)景,幫助網(wǎng)站專注于最重要的指標(biāo)以提升用戶體驗(yàn)。

          在 2020 年主要關(guān)注三個(gè)方面:加載、交互性和視覺(jué)穩(wěn)定性,并包括以下指標(biāo):

          衡量所有 Core Web Vitals 最簡(jiǎn)單的方法就是使用 web-vitals 庫(kù),使用起來(lái)就像調(diào)用單個(gè)函數(shù)一樣簡(jiǎn)單。

          import?{getCLS,?getFID,?getLCP}?from?'web-vitals';

          getCLS(console.log);
          getFID(console.log);
          getLCP(console.log);

          也可以使用 Chrome 插件 Web Vitals Chrome 來(lái)幫助我們測(cè)量這些指標(biāo)。

          如果想要直接通過(guò) Web API 來(lái)獲取這些指標(biāo)的話可以參考下面的獲取方法:

          • 在JavaScript中測(cè)量LCP
          • 在JavaScript中測(cè)量FID
          • 在JavaScript中測(cè)量CLS

          LCP Largest Contentful Paint 最大內(nèi)容繪制

          LCP用于衡量標(biāo)準(zhǔn)報(bào)告視口內(nèi)可見(jiàn)的最大圖像或文本塊的渲染時(shí)間,為了提供良好的用戶體驗(yàn),網(wǎng)站應(yīng)努力在開(kāi)始加載頁(yè)面的前2.5 秒內(nèi)進(jìn)行“最大內(nèi)容繪制”。

          優(yōu)化LCP方案

          FID First Input Delay 首次交互延遲

          FID用于衡量從用戶第一次與頁(yè)面進(jìn)行交互到瀏覽器實(shí)際上能夠開(kāi)始處理事件處理程序的時(shí)間。為了提供良好的用戶體驗(yàn),網(wǎng)站應(yīng)努力使首次輸入延遲小于 100 毫秒。

          下圖中米色方塊代表主線程處于忙碌階段,如果此時(shí)用戶進(jìn)行輸入,則它必須等待任務(wù)完成時(shí)才能響應(yīng)輸入,等待的時(shí)間也就是此頁(yè)面上該用戶的 FID 值。

          優(yōu)化FID方案

          CLS Cumulative Layout Shift 累積布局偏移

          CLS用于測(cè)量在頁(yè)面的整個(gè)生命周期中發(fā)生的每一個(gè)意外的布局移動(dòng),它代表所有單獨(dú)布局轉(zhuǎn)移分?jǐn)?shù)的總和。為了提供良好的用戶體驗(yàn),網(wǎng)站應(yīng)努力使CLS分?jǐn)?shù)小于0.1。

          布局偏移分?jǐn)?shù)

          瀏覽器將查看視口大小以及兩個(gè)渲染幀之間的視口中不穩(wěn)定元素的移動(dòng)。

          布局偏移分?jǐn)?shù)是該運(yùn)動(dòng)的兩個(gè)指標(biāo)的乘積:影響分?jǐn)?shù)和距離分?jǐn)?shù)

          layout?shift?score?=?impact?fraction?*?distance?fraction

          影響分?jǐn)?shù)

          前一幀和當(dāng)前幀的所有不穩(wěn)定元素的可見(jiàn)區(qū)域的并集(占視口總面積的一部分)是當(dāng)前幀的影響分?jǐn)?shù)。

          在上圖中,有一個(gè)元素在一幀中占據(jù)了視口的一半。然后,在下一幀中,元素下移視口高度的 25%。紅色的虛線矩形表示兩個(gè)幀中元素的可見(jiàn)區(qū)域的并集,在這種情況下,其為總視口的 75%,因此其影響分?jǐn)?shù)為 0.75。

          距離分?jǐn)?shù)

          布局偏移分?jǐn)?shù)方程的另一部分測(cè)量不穩(wěn)定元素相對(duì)于視口移動(dòng)的距離。距離分?jǐn)?shù)是任何不穩(wěn)定元素在框架中(水平或垂直)移動(dòng)的最大距離除以視口的最大尺寸(寬度或高度,以較大者為準(zhǔn))。

          在上圖中,最大視口尺寸是高度,不穩(wěn)定元素已經(jīng)移動(dòng)了視口高度的 25%,所以距離分?jǐn)?shù)是 0.25。

          所以,布局偏移分?jǐn)?shù):0.75 * 0.25 = 0.1875

          優(yōu)化CLS方案

          好了,本文到這里就結(jié)束了,文中參考的鏈接都整理到了下面,大家可以自行查閱。

          站在巨人的肩膀上

          • 圖解 Google V8 李兵
          • 瀏覽器工作原理與實(shí)踐 李兵
          • Core Web Vitals https://web.dev/vitals/
          • web-vitals https://github.com/GoogleChrome/web-vitals/
          • LCP https://web.dev/lcp/
          • FID https://web.dev/fid/
          • CLS https://web.dev/cls/
          • 優(yōu)化FID方案 https://web.dev/optimize-fid/
          • 優(yōu)化LCP方案 https://web.dev/optimize-lcp/
          • 優(yōu)化CLS方案 https://web.dev/optimize-cls/


          推薦公眾號(hào)


          微信搜 “前端GitHub”,回復(fù) “電子書” 即可以獲得?160?本前端精華書籍哦。

          往期精文

          瀏覽 38
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲欧美精品久久久久 | 亚洲天堂AAA | 亚洲精品suv视频 | 久草中文91 | 日韩黄色在线免费观看 |