摘要:當這些異步任務發生的時候,它們將會被放入瀏覽器的事件任務隊列中去,等到運行時執行線程空閑時候才會按照隊列先進先出的原則被一一執行,但終究還是單線程。
瀏覽器是多進程的 Browser進程:
瀏覽器的主進程(負責協調、主控),只有一個。
負責瀏覽器界面顯示,與用戶交互。如前進,后退等
負責各個頁面的管理,創建和銷毀其他進程
將Renderer進程得到的內存中的Bitmap,繪制到用戶界面上
網絡資源的管理,下載等
第三方插件進程:每種類型的插件對應一個進程,僅當使用該插件時才創建
GPU進程:最多一個,用于3D繪制等
瀏覽器渲染進程(瀏覽器內核)(Renderer進程,內部是多線程的):默認每個Tab頁面一個進程,互不影響。主要作用為
頁面渲染,腳本執行,事件處理等
上面的進程會輔助這個進程的執行,其中渲染進程對頁面的影響最重要
怎么查看瀏覽器進程情況打開Chrome Shift+Esc;我們可以看到進程情況,Chrome圖標就是Browser主進程
避免單個page crash影響整個瀏覽器
避免第三方插件crash影響整個瀏覽器
多進程充分利用多核優勢
方便使用沙盒模型隔離插件等進程,提高瀏覽器穩定性
簡單點理解:如果瀏覽器是單進程,那么某個Tab頁崩潰了,就影響了整個瀏覽器,體驗有多差;同理如果是單進程,插件崩潰了也會影響整個瀏覽器;而且多進程還有其它的諸多優勢,當然內存等資源消耗也會更大
重點是瀏覽器內核(渲染進程)該進程有多個線程完成 GUI渲染線程負責渲染瀏覽器界面,解析HTML,CSS,構建DOM樹和RenderObject樹,布局和繪制等。
當界面需要重繪(Repaint)或由于某種操作引發回流(reflow)時,該線程就會執行
注意,GUI渲染線程與JS引擎線程是互斥的,當JS引擎執行時GUI線程會被掛起(相當于被凍結了),GUI更新會被保存在一個隊列中等到JS引擎空閑時立即被執行。
也稱為JS內核,負責處理Javascript腳本程序。(例如V8引擎)
JS引擎線程負責解析Javascript腳本,運行代碼。
JS引擎一直等待著任務隊列中任務的到來,然后加以處理,一個Tab頁(renderer進程)中無論什么時候都只有一個JS線程在運行JS程序
同樣注意,GUI渲染線程與JS引擎線程是互斥的,所以如果JS執行的時間過長,這樣就會造成頁面的渲染不連貫,導致頁面渲染加載阻塞。
歸屬于瀏覽器而不是JS引擎,用來控制事件循環(可以理解,JS引擎自己都忙不過來,需要瀏覽器另開線程協助)
當JS引擎執行代碼塊如setTimeOut時(也可來自瀏覽器內核的其他線程,如鼠標點擊、AJAX異步請求等),會將對應任務添加到事件線程中
當對應的事件符合觸發條件被觸發時,該線程會把事件添加到待處理隊列的隊尾,等待JS引擎的處理
注意,由于JS的單線程關系,所以這些待處理隊列中的事件都得排隊等待JS引擎處理(當JS引擎空閑時才會去執行)
傳說中的setInterval與setTimeout所在線程
瀏覽器定時計數器并不是由JavaScript引擎計數的,(因為JavaScript引擎是單線程的, 如果處于阻塞線程狀態就會影響記計時的準確)
因此通過多帶帶線程來計時并觸發定時(計時完畢后,添加到事件隊列中,等待JS引擎空閑后執行)
注意,W3C在HTML標準中規定,規定要求setTimeout中低于4ms的時間間隔算為4ms。
在XMLHttpRequest在連接后是通過瀏覽器新開一個線程請求
將檢測到狀態變更時,如果設置有回調函數,異步線程就產生狀態變更事件,將這個回調再放入事件隊列中。再由JavaScript引擎執行。
Browser進程收到用戶請求,首先需要獲取頁面內容(譬如通過網絡下載資源),隨后將該任務通過RendererHost接口傳遞給Render進程
Renderer進程的Renderer接口收到消息,簡單解釋后,交給渲染線程,然后開始渲染
渲染線程接收請求,加載網頁并渲染網頁,這其中可能需要Browser進程獲取資源和需要GPU進程來幫助渲染
當然可能會有JS線程操作DOM(這樣可能會造成回流并重繪)
最后Render進程將結果傳遞給Browser進程
Browser進程接到結果并將結果繪制出來
渲染進程(瀏覽器內核)線程的關系 GUI渲染線程與JS引擎線程互斥由于JavaScript是可操縱DOM的,如果在修改這些元素屬性同時渲染界面(即JS線程和UI線程同時運行),那么渲染線程前后獲得的元素數據就可能不一致了。
因此為了防止渲染出現不可預期的結果,瀏覽器設置GUI渲染線程與JS引擎為互斥的關系,當JS引擎執行時GUI線程會被掛起,
GUI更新則會被保存在一個隊列中等到JS引擎線程空閑時立即被執行。
從上述的互斥關系,可以推導出,JS如果執行時間過長就會阻塞頁面。
譬如,假設JS引擎正在進行巨量的計算,此時就算GUI有更新,也會被保存到隊列中,等待JS引擎空閑后執行。
然后,由于巨量計算,所以JS引擎很可能很久很久后才能空閑,自然會感覺到巨卡無比。
所以,要盡量避免JS執行時間過長,這樣就會造成頁面的渲染不連貫,導致頁面渲染加載阻塞的感覺。
JavaScript引擎是單線程運行的,JavaScript中耗時的I/O操作都被處理為異步操作,它們包括鍵盤、鼠標I/O輸入輸出事件、窗口大小的resize事件、定時器(setTimeout、setInterval)事件、Ajax請求網絡I/O回調等。當這些異步任務發生的時候,它們將會被放入瀏覽器的事件任務隊列中去,等到JavaScript運行時執行線程空閑時候才會按照隊列先進先出的原則被一一執行,但終究還是單線程。
創建Worker時,JS引擎向瀏覽器申請開一個子線程(子線程是瀏覽器開的,完全受主線程控制,而且不能操作DOM)
JS引擎線程與worker線程間通過特定的方式通信(postMessage API,需要通過序列化對象來與線程交互特定的數據)
//主線程 main.js var worker = new Worker("worker.js"); worker.onmessage = function(event){ // 主線程收到子線程的消息 }; // 主線程向子線程發送消息 worker.postMessage({ type: "start", value: 12345 }); //web worker.js onmessage = function(event){ // 收到 }; postMessage({ type: "debug", message: "Starting processing..." });瀏覽器渲染流程 拿到內容
瀏覽器根據 DNS 服務器得到域名的 IP 地址
向這個 IP 的機器發送 HTTP 請求
服務器收到、處理并返回 HTTP 請求
瀏覽器得到返回內容
解析內容建立Rendering Tree 解析HTMl構建domdom作用: HTMLDOM是HTML Document Object Model(文檔對象模型)的縮寫,HTML DOM則是專門適用于HTML/XHTML的文檔對象模型。熟悉軟件開發的人員可以將HTML DOM理解為網頁的API。它將網頁中的各個元素都看作一個個對象,從而使網頁中的元素也可以被計算機語言獲取或者編輯。
dom規定
整個文檔是一個文檔節點
每個HTML標簽是一個元素節點
包含在HTML元素中的文本是文本節點
每一個HTML屬性是一個屬性節點(屬性節點是另一個層面的理解,在瀏覽器后臺打印的時候,不存在屬性節點)
注釋屬于注釋節點
解析過程:瀏覽器會自動把HTML文檔解析為一個“文檔對象模型”,即Document Object Model,簡稱DOM,這是一個樹形結構,樹根是Document對象,樹干是網頁的根元素,然后分出兩個枝丫,一個是
,一個是,然后網頁上的其他標簽就是這棵樹上的樹葉和樹枝了,通過這個結構,就可以查找和控制網頁上的任何一個元素了。因此,可以這么說,網頁上的任何元素都是Document對象的子對象。 解析CSS產生CSS規則樹,css是由多帶帶的下載線程異步下載的,本身不會阻塞Dom加載,它和DOM結構比較像然后結合DOM生成RenderTree Javascript解析, 通過 DOM API 和 CSSOM API 來操作 DOM Tree 和 CSS Rule Tree。 布局render樹(Layout/reflow),負責各元素尺寸、位置的計算 繪制render樹(paint),繪制頁面像素信息 瀏覽器會將各層的信息發送給GPU,GPU會將各層合成(composite),顯示在屏幕上 渲染過程中的問題 DOMContentLoaded與onload當 DOMContentLoaded 事件觸發時,僅當DOM加載完成,不包括樣式表,圖片
當 onload 事件觸發時,頁面上所有的DOM,樣式表,腳本,圖片都已經加載完成了。 (渲染完畢了)
DOMContentLoaded -> load
瀏覽器如果渲染過程中遇到JS文件怎么處理?上面說過GUI渲染線程與JS引擎線程是互斥的,所以渲染過程中,如果遇到
沒有 defer 或 async,瀏覽器會立即加載并執行指定的腳本,也就是說不等待后續載入的文檔元素,讀到就加載并執行。
(延遲執行)defer 屬性表示延遲執行引入的 JavaScript,即這段 JavaScript 加載時 HTML 并未停止解析,這兩個過程是并行的。整個 document 解析完畢且 defer-script 也加載完成之后(這兩件事情的順序無關),會執行所有由 defer-script 加載的 JavaScript 代碼,然后觸發 DOMContentLoaded 事件。
defer 與相比普通 script,有兩點區別:載入 JavaScript 文件時不阻塞 HTML 的解析,執行階段被放到 HTML 標簽解析完成之后。 在加載多個JS腳本的時候,async是無順序的加載,而defer是有順序的加載。
(異步下載)async 屬性表示異步執行引入的 JavaScript,與 defer 的區別在于,如果已經加載好,就會開始執行。也就是加載不阻塞,執行會阻塞。
瀏覽器的回流與重繪 (Reflow & Repaint)瀏覽器使用流式布局模型 (Flow Based Layout)。
有了RenderTree,我們就知道了所有節點的樣式,然后計算他們在頁面上的大小和位置,最后把節點繪制到頁面上。
當Render Tree中部分或全部元素的尺寸、結構、或某些屬性發生改變時,瀏覽器重新渲染部分或全部文檔的過程稱為回流。
頁面首次渲染
瀏覽器窗口大小發生改變
元素尺寸或位置發生改變
元素內容變化(文字數量或圖片大小等等)
元素字體大小變化
添加或者刪除可見的DOM元素
激活CSS偽類(例如::hover)
查詢某些屬性或調用某些方法
重繪當頁面中元素樣式的改變并不影響它在文檔流中的位置時(例如:color、background-color、visibility等),瀏覽器會將新樣式賦予給元素并重新繪制它,這個過程稱為重繪。
參考文章https://segmentfault.com/a/11...
https://juejin.im/post/5a6547...
https://juejin.im/post/5ca0c0...
https://juejin.im/post/5a9923...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/54172.html
摘要:瀏覽器是多進程的詳情看我上篇總結瀏覽器執行機制的文章深入前端徹底搞懂瀏覽器運行機制瀏覽器每打開一個標簽頁,就相當于創建了一個獨立的瀏覽器進程。執行異步操作事件完成,回調函數進入。主線程從讀取回調函數并執行。 最近看了很多關于JS運行機制的文章,每篇都獲益匪淺,但各有不同,所以在這里對這幾篇文章里說的很精辟的地方做一個總結,參考文章鏈接見最后。本文博客地址 了解進程和線程 進程是應用...
摘要:瀏覽器是多進程的詳情看我上篇總結瀏覽器執行機制的文章深入前端徹底搞懂瀏覽器運行機制瀏覽器每打開一個標簽頁,就相當于創建了一個獨立的瀏覽器進程。執行異步操作事件完成,回調函數進入。主線程從讀取回調函數并執行。 最近看了很多關于JS運行機制的文章,每篇都獲益匪淺,但各有不同,所以在這里對這幾篇文章里說的很精辟的地方做一個總結,參考文章鏈接見最后。本文博客地址 了解進程和線程 進程是應用...
摘要:當這些異步任務發生的時候,它們將會被放入瀏覽器的事件任務隊列中去,等到運行時執行線程空閑時候才會按照隊列先進先出的原則被一一執行,但終究還是單線程。 瀏覽器是多進程的 showImg(https://segmentfault.com/img/remote/1460000019706956?w=815&h=517); Browser進程: 瀏覽器的主進程(負責協調、主控),只有一個。 負...
摘要:檢查宏任務隊列,發現有的回調函數立即執行回調函數輸出。接著遇到它的作用是在后將回調函數放到宏任務隊列中這個任務在再下一次的事件循環中執行。 為什么會寫這篇博文呢? 前段時間,和頭條的小伙伴聊天問頭條面試前端會問哪些問題,他稱如果是他面試的話,event-loop肯定是要問的。那天聊了蠻多,event-loop算是給我留下了很深的印象,原因很簡單,因為之前我從未深入了解過,如果是面試的時...
摘要:徹底搞懂執行機制首先我們大家都了解的是,是一門單線程語言,所以我們就可以得出是按照語句順序執行的首先看這個顯然大家都知道結果,依次輸出,然而換一種這個時候再看代碼的順序執行,輸出,,,。不過即使主線程為空,也是達不到的,根據標準,最低是。 徹底搞懂JavaScript執行機制 首先我們大家都了解的是,JavaScript 是一門單線程語言,所以我們就可以得出: JavaScript 是...
閱讀 2770·2021-11-23 09:51
閱讀 3529·2021-10-08 10:17
閱讀 1262·2021-10-08 10:05
閱讀 1310·2021-09-28 09:36
閱讀 1833·2021-09-13 10:30
閱讀 2174·2021-08-17 10:12
閱讀 1670·2019-08-30 15:54
閱讀 2004·2019-08-30 15:53