瀏覽器的事件循環(huán)

參考:https://www.cnblogs.com/caiyy/p/10406934.html

GUI和Web軟件

1台盯、GUI是通過 代碼打包下載 安裝到如手機(jī)上進(jìn)行訪問的過程

2沥割、Web端的軟件是通過 發(fā)布到server或cdn上废岂,網(wǎng)頁通過增量式訪問獲取服務(wù)的

瀏覽器多進(jìn)程

包含一個主進(jìn)程(包含網(wǎng)絡(luò)渲染,頁面管理)敬锐,插件進(jìn)程绳慎,GPU(3d)渲染進(jìn)程(可選)丁存,頁面渲染進(jìn)程(js處理,頁面渲染墓造,事件處理)

渲染進(jìn)程:

1堪伍、broswer主進(jìn)程 進(jìn)行瀏覽器的頁面資源管理 創(chuàng)建和銷毀其他進(jìn)程,頁面交互觅闽,將位圖合并(布局渲染樹)繪制到頁面上

2帝雇、GPU進(jìn)程,硬件加速 只有一個

3蛉拙、插件進(jìn)程 每個類型的插件對應(yīng)一個進(jìn)程

4尸闸、渲染進(jìn)程 每個tab頁一個進(jìn)程,負(fù)責(zé)頁面渲染 腳本執(zhí)行 事件觸發(fā)孕锄,任務(wù)隊列輪詢等

——JS引擎線程(V8引擎):負(fù)責(zé)js腳本解析吮廉,代碼運(yùn)行 與GUI互斥

——GUI渲染線程: 解析html和css,負(fù)責(zé)布局和繪制畸肆,與js引擎線程互斥宦芦,這是由于js可以操作dom,防止渲染前后不一致

——事件觸發(fā)線程:歸屬于瀏覽器轴脐,用于控制事件循環(huán)调卑,當(dāng)事件被觸發(fā)該線程會將對應(yīng)的回調(diào)函數(shù)放到任務(wù)隊列當(dāng)中

——定時觸發(fā)器線程:setTimeout setTnterval W3C中規(guī)定setTimeout低于4ms算4ms 回調(diào)函數(shù)放入任務(wù)隊列

——異步http請求線程:監(jiān)測狀態(tài)變更時產(chǎn)生狀態(tài)變更事件,放入任務(wù)隊列

——任務(wù)隊列輪詢線程:輪詢監(jiān)聽任務(wù)隊列是否為空

webWorker和shareWorker

js是單線程的 當(dāng)有大量運(yùn)算會造成頁面渲染卡頓豁辉,為了避免可以申請一個web worker令野。 js引擎向瀏覽器申請開一個子線程(不可造作dom),js引擎線程和worker線程通過特定的方式通信徽级,計算出結(jié)果后通信給js引擎主線程气破。

webWorker是某個頁面render下的一個線程,不會和其他頁面的render進(jìn)程共享

shareWorder是瀏覽器所有頁面共享的餐抢,是一個單獨(dú)的進(jìn)程

GUI渲染

網(wǎng)頁從白屏到內(nèi)容顯示的時間就是HTML 文檔加載和解析的時間现使。也就是DOMContentLoaded 事件觸發(fā)之前所經(jīng)歷的時間。

js腳本參數(shù)設(shè)置: https://blog.csdn.net/zyj0209/article/details/79698430

由js引擎來解析html生成dom樹旷痕,css解析生成cssdom樹碳锈,js腳本執(zhí)行可以設(shè)置參數(shù)默認(rèn)是

1、同步sync欺抗,當(dāng)執(zhí)行html的過程中遇到j(luò)s腳本售碳,會停止解析html,先去加載執(zhí)行js腳本完畢后繼續(xù)解析html

2、異步async贸人,當(dāng)執(zhí)行html遇到j(luò)s间景,會同時下載js腳本,如果js先加載完就停止解析html先執(zhí)行js腳本艺智,然后解析html或者是這個時候html已經(jīng)加載完畢倘要,那么直接執(zhí)行js,不管是哪一種十拣,DOMContentLoaded都會在html解析完觸發(fā)

3封拧、延后dsync,遇到j(luò)s腳本會進(jìn)行下載夭问,腳本需要等待html解析完才會執(zhí)行泽西,DOMContentLoaded會在js腳本執(zhí)行完了被觸發(fā)

dom樹和cssdom樹結(jié)合為渲染樹render-tree释涛,從根節(jié)點遞歸調(diào)用計算每一個元素的大小凶硅,位置等,給出每個節(jié)點在屏幕上精確的坐標(biāo)世剖,這就是基于渲染樹的布局渲染樹埠胖,之后交給主進(jìn)程進(jìn)行渲染樹的繪制糠溜。

資源阻塞機(jī)制

DOMContentLoaded和load分別標(biāo)識著dom加載完成和dom&&css&&js加載完成

GUI線程中html和css解析是并行的,css不會阻塞html的解析但是會阻塞頁面渲染直撤,所有放在head中盡量早解析

js根據(jù)需要不同可以放在不同的位置非竿,初始化放在head,操作dom放在body末尾或者使用load事件

回流和重繪

render樹中的部分或全部因為元素的尺寸谋竖、布局红柱、隱藏等改變需要重新構(gòu)建稱為回流,如

1蓖乘、頁面初始化锤悄、調(diào)整窗口,改變字體嘉抒,內(nèi)容變化零聚、操作dom、操作css些侍、激活css偽類隶症、操作class屬性、設(shè)置style屬性岗宣、增加或者移除樣式表

2蚂会、如何防止回流:減少逐項修改style最好一次定義在class中更新、避免循環(huán)操作dom耗式、到要頻繁的獲取offset屬性時胁住,不重復(fù)讀取趁猴,將復(fù)雜的元素絕對定位或者固定定位,使用GPU硬件加速創(chuàng)建一個新的復(fù)合圖層

圖層:dom中的每個節(jié)點對應(yīng)一個簡單圖層措嵌,復(fù)合圖層是對簡單圖層的合并躲叼,absolute,fixed布局會脫離文檔流企巢,但是還在當(dāng)前的復(fù)合圖層中,會影響重繪让蕾,但是回流不影響浪规。

當(dāng)使用硬件加速的時候會生成新的復(fù)合圖層,互不影響探孝,設(shè)置transform: translate3d(0,0,0) 或 translateZ(0)笋婿,更多內(nèi)容參考:http://www.reibang.com/p/f8b1d6e598db

proload和prefetch

詳情:https://www.cnblogs.com/xiaohuochai/p/9183874.html

proload提升資源的優(yōu)先級,提升到跟設(shè)置了as屬性的同一優(yōu)先級顿颅,as屬性設(shè)置資源的優(yōu)先級缸濒,不設(shè)置會默認(rèn)為異步請求的優(yōu)先級,很低粱腻。不管資源是否需要都會被加載庇配,并且有回調(diào)函數(shù)。設(shè)置方式<link rel="preload" href="..." as="..." onload="preloadFinished()">

prefetch是預(yù)先加載下一頁可能用到的資源绍些,不可混用捞慌。

事件循環(huán)機(jī)制

更多:https://juejin.im/post/5ec73026f265da76da29cb25

  • 事件循環(huán)機(jī)制的核心是事件觸發(fā)線程,js執(zhí)行棧的過程中觸發(fā)異步任務(wù)柬批,或者是微任務(wù)啸澡,將異步任務(wù)交給相關(guān)的線程,將微任務(wù)放到微任務(wù)隊列氮帐;
  • 當(dāng)執(zhí)行棧執(zhí)行完畢后去查看微任務(wù)嗅虏,執(zhí)行當(dāng)次產(chǎn)生的微任務(wù),這個時候如果有微任務(wù)添加進(jìn)來會繼續(xù)執(zhí)行微任務(wù)直到j(luò)s執(zhí)行棧為空才去渲染上沐;
  • 同時異步任務(wù)完成后會將回調(diào)函數(shù)放到任務(wù)隊列(宏任務(wù))當(dāng)中皮服,當(dāng)執(zhí)行棧結(jié)束&&微任務(wù)結(jié)束,進(jìn)入渲染階段
    1奄容、判斷是否需要重渲染冰更,一般涉及到屏幕刷新率、頁面性能昂勒、程序是否在后臺執(zhí)行蜀细,一般屏幕刷新率為60Hz,戈盈,如果頁面性能過低奠衔,為了保證穩(wěn)定的刷新率會選擇30Hz谆刨,當(dāng)在一次刷新幀內(nèi)發(fā)生多次動畫行為,并不會真實的渲染到頁面归斤,而會被瀏覽器收集起來一次執(zhí)行痊夭;如果程序在后臺執(zhí)行會降低刷新率到4hz甚至更低;如果瀏覽器認(rèn)為渲染不會引起頁面視覺上的變化脏里;如果幀動畫回調(diào)函數(shù)為空(可以通過requestAnimationFrame函數(shù)觸發(fā))她我;滿足以上條件不進(jìn)行渲染
    2、如果判斷需要渲染則進(jìn)行渲染否則直接開始進(jìn)行后續(xù)代碼的執(zhí)行迫横,也是在這里進(jìn)行resize scroll的觸發(fā)番舆,這里瀏覽器會保存一個,目標(biāo)對象矾踱,等到這里派發(fā)事件到目標(biāo)上的時候驅(qū)動目標(biāo)對象的回調(diào)函數(shù)恨狈。觸發(fā)幀動畫回調(diào)(requAnimationFrame);執(zhí)行IntersectionObserver回調(diào)呛讲;繪制頁面禾怠;判斷宏任務(wù)和微任務(wù)隊列為空,執(zhí)行空閑周期算法判斷是否要執(zhí)行requestIdleCallback的回調(diào)函數(shù)
  • 開啟下一輪的事件循環(huán)贝搁,從宏任務(wù)隊列獲取新的任務(wù)放到執(zhí)行棧執(zhí)行

宏任務(wù) macro-task:script整體代碼吗氏、setTimeout、setInterval徘公、setImmediate牲证、I/O、UIrendering

微任務(wù) micro-task:process关面、nextTick坦袍、Promises、Object.observe等太、MutationObserver

注:

  • async await 最終的結(jié)果是返回了promise捂齐,在await后跟隨的語句是同步的,下一行開始的語句是異步的 等同于then后面的微任務(wù)回調(diào)
  • 對于任務(wù)隊列中的任務(wù)缩抡,并不是只有一個奠宜,對于用戶輸入的任務(wù)如鼠標(biāo)鍵盤事件將會優(yōu)先于其他的task,瀏覽器在保證順序的前提下將會分配給用戶事件4/3的優(yōu)先權(quán)
  • requestAnimationFrame函數(shù)是在頁面重新渲染之前的最后一步調(diào)用瞻想,很可能在宏任務(wù)之后不進(jìn)行調(diào)用
  • requestIdleCallback(fn, deadline)函數(shù)是瀏覽器提供的空閑調(diào)度算法压真,將一些計算量大而且又不緊急的任務(wù)放到空閑時間去執(zhí)行,每次使用的時候要去調(diào)用timeRemaining()函數(shù)獲取deadline來判斷是否有空余時間可以使用蘑险,如果有更高優(yōu)先級的任務(wù)出現(xiàn)則將在沒有渲染任務(wù)的時候則會動態(tài)的將剩余時間設(shè)置為0滴肿;需要注意的是每次當(dāng)瀏覽器是空閑的也會有deadline為50ms這是為了應(yīng)對用戶的交互操作發(fā)生時,確保用戶在無感知的延遲下得到回應(yīng)

例題:https://blog.csdn.net/weixin_34176694/article/details/91400057

瀏覽器渲染之前做了什么

更多:https://juejin.im/post/5e6394b4e51d4526e32c3cef

需要注意的是佃迄,每次渲染的的條件是js的執(zhí)行棧為空泼差,也就是觸發(fā)了requestAnimationFrame()方法贵少,所以在執(zhí)行代碼的時候,如


document.addElementListener('click', function(){console.log(1, promise.resolve().then(() =>{console.log(2)}))})

document.addElementListener('click', function(){console.log(3, promise.resolve().then(() =>{console.log(4)}))})

在代碼中調(diào)用堆缘,會在js執(zhí)行棧中加載一個腳本文件滔灶,第一個監(jiān)聽器觸發(fā)后,腳本文件scripts還在所以這個時候不能去執(zhí)行微任務(wù)吼肥,還是繼續(xù)執(zhí)行宏任務(wù)录平,執(zhí)行完后退出js堆棧,這時才去清空微任務(wù)缀皱,結(jié)果:1=>3=>2=>4

如果是在頁面上點擊觸發(fā)萄涯,沒有初始的js腳本,則會在第一個監(jiān)聽觸發(fā)后判斷堆棧為空去執(zhí)行微任務(wù)唆鸡,結(jié)果為1=>2=>3=>4


image.png

這里有一個圖,三個環(huán)枣察,中間是事件循環(huán)争占,左邊是其他的事件(宏任務(wù)、微任務(wù))序目,右邊是瀏覽器渲染臂痕,在左邊完成后,會按照順序推到中間的js執(zhí)行棧中猿涨,在js執(zhí)行棧為空的時候觸發(fā)requestAnimationFrame()去進(jìn)行頁面渲染握童,如下代碼,微任務(wù)執(zhí)行后繼續(xù)添加了新的任務(wù)到j(luò)s棧中叛赚,會循環(huán)執(zhí)行

function loop(){promise.resolve().then(loop)}
loop()
setTimeout(() => {
  console.log("sto")
  requestAnimationFrame(() => console.log("rAF"))
})
setTimeout(() => {
  console.log("sto")
  requestAnimationFrame(() => console.log("rAF"))
})

如果用setTimeout循環(huán)來進(jìn)行動畫的循環(huán)處理澡绩,會比requestAnimationFrame()執(zhí)行的次數(shù)多,這是因為瀏覽器一般為60Hz也就是一秒最多渲染60次俺附,這里是由于人眼的感知所決定肥卡,60Hz已經(jīng)是較為流暢的實現(xiàn),當(dāng)然與硬件顯卡之類的設(shè)備也有關(guān)系事镣,硬件決定上限步鉴,性能平衡決定結(jié)果;所以setTimeout最多可以達(dá)到瀏覽器的閾值璃哟,當(dāng)然多余的調(diào)用就被浪費(fèi)了氛琢,同時可能會因為在每一個動畫幀調(diào)用次數(shù)不同而出現(xiàn)漂移,也可能因為在沒有匹配到動畫幀而丟失渲染随闪,不可控阳似,如上面的代碼第二段,瀏覽器期待在定時器之間不穿插渲染蕴掏,所以會將兩次渲染合并到一起障般,結(jié)果是:sto sto rAF rAF
而requestAnimationFrame是在每一次渲染之前調(diào)用调鲸,更加科學(xué)的用于動畫的處理,有些人會把requestAnimationFrame方法歸類為和setTimeout一樣都屬于宏任務(wù)隊列挽荡,但是實際上來說與宏任務(wù)和微任務(wù)無關(guān)它只和瀏覽器渲染相關(guān)藐石,在瀏覽器刷新前執(zhí)行

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市定拟,隨后出現(xiàn)的幾起案子于微,更是在濱河造成了極大的恐慌,老刑警劉巖青自,帶你破解...
    沈念sama閱讀 212,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件株依,死亡現(xiàn)場離奇詭異,居然都是意外死亡延窜,警方通過查閱死者的電腦和手機(jī)恋腕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來逆瑞,“玉大人荠藤,你說我怎么就攤上這事』窀撸” “怎么了哈肖?”我有些...
    開封第一講書人閱讀 158,369評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長念秧。 經(jīng)常有香客問我淤井,道長,這世上最難降的妖魔是什么摊趾? 我笑而不...
    開封第一講書人閱讀 56,799評論 1 285
  • 正文 為了忘掉前任币狠,我火速辦了婚禮,結(jié)果婚禮上严就,老公的妹妹穿的比我還像新娘总寻。我一直安慰自己,他們只是感情好梢为,可當(dāng)我...
    茶點故事閱讀 65,910評論 6 386
  • 文/花漫 我一把揭開白布渐行。 她就那樣靜靜地躺著,像睡著了一般铸董。 火紅的嫁衣襯著肌膚如雪祟印。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,096評論 1 291
  • 那天粟害,我揣著相機(jī)與錄音蕴忆,去河邊找鬼。 笑死悲幅,一個胖子當(dāng)著我的面吹牛套鹅,可吹牛的內(nèi)容都是我干的站蝠。 我是一名探鬼主播,決...
    沈念sama閱讀 39,159評論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼卓鹿,長吁一口氣:“原來是場噩夢啊……” “哼菱魔!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起吟孙,我...
    開封第一講書人閱讀 37,917評論 0 268
  • 序言:老撾萬榮一對情侶失蹤澜倦,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后杰妓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體藻治,經(jīng)...
    沈念sama閱讀 44,360評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,673評論 2 327
  • 正文 我和宋清朗相戀三年巷挥,在試婚紗的時候發(fā)現(xiàn)自己被綠了桩卵。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,814評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡倍宾,死狀恐怖吸占,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情凿宾,我是刑警寧澤,帶...
    沈念sama閱讀 34,509評論 4 334
  • 正文 年R本政府宣布兼蕊,位于F島的核電站初厚,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏孙技。R本人自食惡果不足惜产禾,卻給世界環(huán)境...
    茶點故事閱讀 40,156評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望牵啦。 院中可真熱鬧亚情,春花似錦、人聲如沸哈雏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽裳瘪。三九已至土浸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間彭羹,已是汗流浹背黄伊。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留派殷,地道東北人还最。 一個月前我還...
    沈念sama閱讀 46,641評論 2 362
  • 正文 我出身青樓墓阀,卻偏偏與公主長得像,于是被迫代替她去往敵國和親拓轻。 傳聞我的和親對象是個殘疾皇子斯撮,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,728評論 2 351