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