chrome官方解釋在導航欄輸入url敲下回車後發生了什麼?

這是來自谷歌官方博客: inside modern browser 的四篇系列文章,也有人作了全文翻譯,參見承香墨影。本文可看做一個abstract,對全文進行了重點摘要,以期讀完後對chrome瀏覽器的體系結構,處理機制有整體的瞭解。有個經典的前端面試問題:在導航欄輸入url敲下回車後發生了什麼?本文可以看做一個比較全面、深入一點的回答。

瀏覽器體系結構

  • CPU 一個接一個地處理多項任務
  • GPU 同時、跨內核處理多個簡單任務

開啓application時,機器的物理硬件在最底層,中間是操作系統,最上層纔是應用本身。

瀏覽器沒有一定之規。有的是單進程多線程,有的是多進程,一個進程有少量的多個線程IPC。

進程 功能
Browser controls ‘chrome’ part of the app and privileged parts such as network requests and file access
Renderer anything inside of the tab where a website is displayed
Plugin any plugins used by the web like flash
GPU Handles GPU tasks in isolation from other processes. It is separated into different process because GPUs handles requests from multiple apps and draw them in the same surface.
  • 出於安全和沙箱考慮,每個tab有獨立的renderer process
  • 因爲每個進程有獨立的內存空間,這會造成一定的資源浪費(can’t share common infrasructure like v8), chrome限制了它可以啓動的進程數量。如果達到了限制,則會把多個tab上那些同源的網頁合併到一個進程中。
  • chrome 正在做的事情是,把瀏https://www.cnblogs.com/peida/archive/2013/03/05/2943698.html覽器程序的每個部分作爲一項可拆分的服務。當 Chrome 在強大的硬件上運行時,它可能會將每個服務拆分爲不同的進程,從而提供更高的穩定性,但如果它位於資源約束的設備上,Chrome 會將服務整合到一個進程中,從而節省內存佔用。
  • 整合進程以節省資源的策略已經被用於其他平臺,如andriod上。

在這裏插入圖片描述

每個frame有獨立渲染進程,站點隔離

導航過程

tab之外的一切都是瀏覽器進程控制。瀏覽器進程包括:

線程 功能
UI線程 繪製按鈕和輸入框
網絡線程 處理網絡請求和堆棧
存儲線程 控制對文件的讀取

輸入url是由UI線程控制的

  1. 處理輸入: isSearchInput? to search engine : to the site you requested
  2. 開始導航: UI線程控制loading spinner, 網絡線程建立連接
  3. 讀取res:網絡線程,response’s Content-Type header不一定可信,嗅探MIME TYPE判斷響應體的格式,安全檢查,CORB。
  • html ----> 交給renderer進程渲染
  • zip ----> 下載管理器download
  1. UI線程找到一個渲染進程,優化:在步驟2的同時,UI線程主動去找或者開啓一個渲染進程。
  2. commit navigation:瀏覽器進程和渲染進程IPC,完成導航。地址欄、session 歷史更新。
    IPC between the browser and the renderer process when rendering page
    導航commit後,渲染進程結束渲染,所有onload事件都觸發、執行完畢後,IPC告訴瀏覽器進程,UI線程停止loading spinner

導航到別的站點前,會處理所有的beforeunload事件
新導航會新開一個渲染進程,老的渲染新城處理unload事件等

  • service worker:在渲染進程中運行,從緩存中加載資源
  • 導航預加載:加載資源和開啓service worker同時進行

渲染進程

渲染進程包括:

  • 主線程
  • service worker/web worker 線程
  • compositor thread
  • raster thread

link, img 會preload, 但script 會阻塞html繼續解析,直至script被執行完

  • async/defer

  • js module

  • < link rel='proload >
  • 先計算每個node 的樣式,主線程再算出整體的佈局樹,包括x,y 座標和盒模型的大小

  • layout tree 類似dom tree,但只包含頁面可見部分的結構。display: none 會被忽略。visibility: hidden不會,僞元素如果有content也不會。

  • 這之後要決定繪製的順序(層次)。z-index。主線程會生成paint records,一條條記錄繪製的順序。

  • repaint 很費cpu。 大多數瀏覽器刷新頁面的速度是60次/秒。最佳實踐是把js操作分成小粒度,用requestAnimationFrame()來調用。

  • 組合。turn all above information into pixels(rasterizing/位圖化)。

  • css: will-change 提醒瀏覽器該元素要分成單獨的層。

  • compositor frame 被提交給瀏覽器進程。如果滾動,compositor thread 會生成一個新的compositor frame 給GPU。

componsitor處理輸入交互

對瀏覽器而言,任何用戶的gesture都屬於input

  • 瀏覽器進程先獲取到gesture, 再把event的類型和座標發給渲染進程
  • 渲染進程找到事件的目標,and run attached event listeners.
  • compositor thread marks ‘non-fast scrollable region’, a region of the page that has event handlers attached. 如果事件在該區域發生了,compositor thread就發送input event 給主線程。如果是在其他區域有input, compositor thread 繼續組裝新的frame,不用等main thread.
  • 事件委託可能會不必要地擴大了non-fast scrollable region, 造成平滑滾動效果被減弱。想要暗示瀏覽器的組裝器繼續組裝而不是等待主線程,可以這麼做:
// 但實際上,chrome會報錯說can't prevent default inside passive...建議直接用css: touch-action來改。
document.body.addEventListener('touchstart', event => {
    if (event.target === area) {
        event.preventDefault()
    }
 }, {passive: true});
  • 離散的事件立即分發,連續事件如wheel, mousewheel, mousemove, pointermove, touchmove 會延遲分發,卡在requestAnimationFrame的每一幀變換上。(input事件的傳達速度多在60fps以上,這是一種優化)
  • getCoalescedEvents 來獲取這些被合併的事件
window.addEventListener('pointermove', event => {
    const events = event.getCoalescedEvents();
    for (let event of events) {
        const x = event.pageX;
        const y = event.pageY;
        // draw a line using x and y coordinates.
    }
})
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章