前端性能優(yōu)化原理與實踐(三)

摘自前端性能優(yōu)化原理與實踐

DOM 優(yōu)化原理與基本實踐

JS是很快的锈遥,在 JS中修改DOM對象也是很快的。在JS的世界里象迎,一切是簡單的凡橱、迅速的。但 DOM操作并非 JS 一個人的獨舞台汇,而是兩個模塊之間的協(xié)作苛骨。

JS引擎和渲染引擎(瀏覽器內(nèi)核)是獨立實現(xiàn)的篱瞎。當(dāng)我們用 JS去操作 DOM 時,本質(zhì)上是JS引擎和渲染引擎之間進行了跨界交流痒芝。這個跨界交流的實現(xiàn)并不簡單俐筋,它依賴了橋接接口作為橋梁

對 DOM 的修改引發(fā)樣式的更迭

我們對 DOM的操作都不會局限于訪問严衬,而是為了修改它澄者。當(dāng)我們對DOM的修改會引發(fā)它外觀(樣式)上的改變時,就會觸發(fā)回流或重繪请琳。

這個過程本質(zhì)上還是因為我們對DOM的修改觸發(fā)了渲染樹(Render Tree)的變化所導(dǎo)致的粱挡,重繪不一定導(dǎo)致回流,回流一定會導(dǎo)致重繪俄精。硬要比較的話询筏,回流比重繪做的事情更多,帶來的開銷也更大嘀倒。但這兩個說到底都是吃性能的屈留,所以都不是什么善茬。我們在開發(fā)中测蘑,要從代碼層面出發(fā)灌危,盡可能把回流和重繪的次數(shù)最小化。

DOM Fragment

DocumentFragment 接口表示一個沒有父級文件的最小文檔對象碳胳。它被當(dāng)做一個輕量版的Document使用勇蝙,用于存儲已排好版的或尚未打理好格式的XML片段。因為DocumentFragment不是真實DOM 樹的一部分挨约,它的變化不會引起DOM 樹的重新渲染的操作(reflow)味混,且不會導(dǎo)致性能等問題。作為脫離了真實DOM樹的容器出現(xiàn)诫惭,用于緩存批量化的DOM操作翁锡。

let container = document.getElementById('container')
// 創(chuàng)建一個DOM Fragment對象作為容器
let content = document.createDocumentFragment()
for(let count=0;count<10000;count++){
  // span此時可以通過DOM API去創(chuàng)建
  let oSpan = document.createElement("span")
  oSpan.innerHTML = '我是一個小測試'
  // 像操作真實DOM一樣操作DOM Fragment對象
  content.appendChild(oSpan)
}
// 內(nèi)容處理好了,最后再觸發(fā)真實DOM的更改
container.appendChild(content)

我們運行這段代碼,可以得到與前面兩種寫法相同的運行結(jié)果夕土。
可以看出馆衔,DOM Fragment對象允許我們像操作真實 DOM一樣去調(diào)用各種各樣的DOM API,我們的代碼質(zhì)量因此得到了保證怨绣。并且它的身份也非常純粹:當(dāng)我們試圖將其append進真實DOM時角溃,它會在乖乖交出自身緩存的所有后代節(jié)點后全身而退,完美地完成一個容器的使命篮撑,而不會出現(xiàn)在真實的 DOM結(jié)構(gòu)中减细。這種結(jié)構(gòu)化、干凈利落的特性赢笨,使得DOM FragmentDOM Fragment作為經(jīng)典的性能優(yōu)化手段大受歡迎未蝌。

Event Loop 與異步更新策略

Micro-Task 與 Macro-Task

事件循環(huán)中的異步隊列有兩種:macro(宏任務(wù))隊列和 micro(微任務(wù))隊列驮吱。

  • 常見的 macro-task比如: setTimeoutsetInterval树埠、 setImmediate糠馆、script(整體代碼)、I/O操作怎憋、UI渲染等又碌。
  • 常見的micro-task比如:process.nextTickPromise绊袋、MutationObserver等毕匀。

Event Loop 過程解析

一個完整的 Event Loop過程,可以概括為以下階段:

  • 初始狀態(tài):調(diào)用棸┍穑空皂岔。micro 隊列空,macro隊列里有且只有一個 script腳本(整體代碼)展姐。

  • 全局上下文(script 標(biāo)簽)被推入調(diào)用棧躁垛,同步代碼執(zhí)行。在執(zhí)行的過程中圾笨,通過對一些接口的調(diào)用教馆,可以產(chǎn)生新的 macro-taskmicro-task,它們會分別被推入各自的任務(wù)隊列里擂达。同步代碼執(zhí)行完了土铺,script 腳本會被移出macro隊列,這個過程本質(zhì)上是隊列的 macro-task的執(zhí)行和出隊的過程板鬓。

  • 上一步我們出隊的是一個macro-task悲敷,這一步我們處理的是 micro-task。但需要注意的是:當(dāng) macro-task出隊時俭令,任務(wù)是一個一個執(zhí)行的后德;而 micro-task出隊時,任務(wù)是一隊一隊執(zhí)行的(如下圖所示)抄腔。因此探遵,我們處理micro隊列這一步,會逐個執(zhí)行隊列中的任務(wù)并把它出隊妓柜,直到隊列被清空。
  • 執(zhí)行渲染操作涯穷,更新界面(敲黑板劃重點)棍掐。

  • 檢查是否存在Web worker任務(wù),如果有拷况,則對其進行處理 作煌。(上述過程循環(huán)往復(fù)掘殴,直到兩個隊列都清空)

異步更新策略

當(dāng)我們使用VueReact提供的接口去更新數(shù)據(jù)時,這個更新并不會立即生效粟誓,而是會被推入到一個隊列里奏寨。待到適當(dāng)?shù)臅r機,隊列中的更新任務(wù)會被批量觸發(fā)鹰服。這就是異步更新病瞳。

最典型的例子,比如有時我們會遇到這樣的情況:

// 任務(wù)一
this.content = '第一次測試'
// 任務(wù)二
this.content = '第二次測試'
// 任務(wù)三
this.content = '第三次測試'

我們在三個更新任務(wù)中對同一個狀態(tài)修改了三次悲酷,如果我們采取傳統(tǒng)的同步更新策略套菜,那么就要操作三次DOM。但本質(zhì)上需要呈現(xiàn)給用戶的目標(biāo)內(nèi)容其實只是第三次的結(jié)果设易,也就是說只有第三次的操作是有意義的——我們白白浪費了兩次計算逗柴。

但如果我們把這三個任務(wù)塞進異步更新隊列里,它們會先在 JS的層面上被批量執(zhí)行完畢顿肺。當(dāng)流程走到渲染這一步時戏溺,它僅僅需要針對有意義的計算結(jié)果操作一次DOM——這就是異步更新的妙處。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末屠尊,一起剝皮案震驚了整個濱河市旷祸,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌知染,老刑警劉巖肋僧,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異控淡,居然都是意外死亡嫌吠,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門掺炭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來辫诅,“玉大人,你說我怎么就攤上這事涧狮】话” “怎么了?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵者冤,是天一觀的道長肤视。 經(jīng)常有香客問我,道長涉枫,這世上最難降的妖魔是什么邢滑? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮愿汰,結(jié)果婚禮上困后,老公的妹妹穿的比我還像新娘乐纸。我一直安慰自己,他們只是感情好摇予,可當(dāng)我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布汽绢。 她就那樣靜靜地躺著,像睡著了一般侧戴。 火紅的嫁衣襯著肌膚如雪宁昭。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天救鲤,我揣著相機與錄音久窟,去河邊找鬼。 笑死本缠,一個胖子當(dāng)著我的面吹牛斥扛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播丹锹,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼稀颁,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了楣黍?” 一聲冷哼從身側(cè)響起匾灶,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎租漂,沒想到半個月后阶女,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡哩治,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年秃踩,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片业筏。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡憔杨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蒜胖,到底是詐尸還是另有隱情消别,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布台谢,位于F島的核電站寻狂,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏朋沮。R本人自食惡果不足惜荆虱,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧怀读,春花似錦、人聲如沸骑脱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽叁丧。三九已至啤誊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間拥娄,已是汗流浹背蚊锹。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留稚瘾,地道東北人牡昆。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像摊欠,于是被迫代替她去往敵國和親丢烘。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容