深入(劃掉) 觀察event loop

event loop拟糕,是一個比較抽象的東西屡限。主要因為兩個方面

  • 文檔看上去很復(fù)雜兼耀;
  • 難以眼見為實压昼。如何確認自己真的明白整個過程求冷。如何把event loop的理論聯(lián)系到實際,或者更進一步窍霞,如何用于編程和debug匠题。

作為一個習(xí)慣了所見即所得的前端,我希望能夠確認我yy出來的流程是否和瀏覽器執(zhí)行的真實情況一致但金,同時能夠真正作用于編程和debug中

console.log韭山?

最初接觸event loop(之前寫(翻譯)過的一篇博客),我曾經(jīng)嘗試過console.log 冷溃。效果其實并沒有很好钱磅,更像是,我大約知道了這個理論似枕,然后根據(jù)現(xiàn)實的情況強行解釋它盖淡。同時中間還有很大的不確定性。比如說如何確認瀏覽器是先執(zhí)行microtaks還是先執(zhí)行渲染凿歼,如何確認一個event loop已經(jīng)執(zhí)行完了褪迟。

那,還有啥子辦法答憔?

最近看了幾場jsconf eu關(guān)于chrome的performance的分享味赃,忽然靈光一現(xiàn),可以利用chrome dev tool>performance來驗證整個過程

event loop

文檔關(guān)于event loop的執(zhí)行說明如下圖:

eventloop.png

task queue包含:

  • Events
  • Parsing
  • Callbacks(setTimeout, etc)
  • Using a resource
  • Reacting to DOM manipulation(node.inserBefore, etc)
    (每個task有自己的task source攀唯,瀏覽器有相當大的裁量權(quán)來決定哪個task source過來的task先執(zhí)行洁桌。)
    執(zhí)行完一個taskQueue,就會執(zhí)行一次microtask侯嘀,把microtask queue全部清干凈
    理論看上去是很清晰的另凌,然而,仍有地方是很容易迷惑的戒幔,比如說:
  1. 如何才算做一個queue吠谢?考慮以下代碼
// Promise runs in microtask
Promise.resolve().then(() => { console.log('microtask ran') })
// is it a queue?
const div = document.querySelector('div')
document.body.insertBefore(document.createElement('div'), div)
// queue ends?
console.log('will microtask run before me?')

結(jié)果似乎不是這樣:

2017-06-02-16-48-25.jpg
2017-06-02-16-47-24.jpg

可以看到,只有在log結(jié)束的時候诗茎,也就是在整個執(zhí)行椆し唬空了的時候才執(zhí)行了microtask。wait敢订,這和(我理解的)文檔說的不一樣M跷邸!難道不是dom manipulation執(zhí)行完了就執(zhí)行microtask么楚午?

so, what's a queue?

根據(jù)上面昭齐,似乎是把一個執(zhí)行棧都執(zhí)行完了,就算一個queue執(zhí)行完了矾柜,就可以進行microtask阱驾。
let's have a try

function log (type) {
  Promise.resolve().then(() => {
    console.log(`microtask added by ${type} runs`)
  })
  console.log(`start log[${Date.now()}]: ${type}`)
}

setTimeout(log.bind(null, 'setTimeout'))

document.addEventListener('DOMContentLoaded', log.bind(null, 'DOMContentLoaded'))

log('global 1')
log('global 2')
2017-06-02-17-15-27.jpg
2017-06-02-17-15-52.jpg
2017-06-02-17-15-03.jpg

確認了兩件事情:

  • 當前執(zhí)行椌兔眨空時才執(zhí)行microtask
  • setTimeout會在其他task queue(此處是Parsing)之后,再執(zhí)行

放大Parse HTML里覆,我們可以看到:

2017-06-02-17-20-59.jpg

microtask執(zhí)行在render(recalculate style和layout)之前

microtask

文檔:

microtask.png

看上去還蠻清晰的

如果在一個microtask里面又指定了一個microtask呢丧荐?

考慮以下代碼:

Promise.resolve().then(log.bind(null, 'promise'))
2017-06-02-18-02-58.jpg

可以看到,microtask里面又指定了一個microtask喧枷,會順序執(zhí)行虹统,而不是留到下一個microtask checkPoint執(zhí)行

render pipeline

實際上對于前面的兩個理論的驗證,單純靠console.log隧甚,也是可以印證的窟却,但是渲染相關(guān),就很難了呻逆。
文檔

2017-06-02-23-02-27.jpg

圖片來自render process model
考慮以下代碼:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>event loop</title>
  <style>
  body {
    height: 2000px;
    background: lightgreen;
  }
  </style>
</head>
<body>
  <div class="animate">lulala</div>
  <script src="./test.js"></script>
</body>
</html>
// your test.js
document.addEventListener('DOMContentLoaded', () => {
  function log (type) {
      Promise.resolve().then(() => {
        console.log(`microtask added by ${type} runs`)
    })
    console.log(`start log[${Date.now()}]: ${type}`)
  }
  setTimeout(() => {
    window.requestAnimationFrame(log.bind(null, 'rAF'))
    window.addEventListener('scroll', log.bind(null, 'scroll'))
    window.scrollTo(0, 3000)
  })

  log('global')
})
2017-06-03-14-57-07.jpg
2017-06-03-14-56-46.jpg

可以看到scroll是在rAF之前被觸發(fā)的夸赫,之后便開始了update layer tree和paint

wait,竟然發(fā)現(xiàn)scroll和rAF之后咖城,都觸發(fā)了microtasks2缤取!

conclusion

哈宜雀,原本是想寫一篇深入event loop的文章切平,寫著變成了如何使用performance觀察event loop???♂

不過在整個嘗試的過程里面,還破除了一些以前模棱兩可的迷信辐董,比如說“不要老是去拿元素屬性悴品,會觸發(fā)重排或者重繪的”,其實不一定的哦简烘,設(shè)置了動畫或者對元素進行了class增刪苔严,然后取元素寬高之類的屬性,的確會導(dǎo)致重排或者重繪的計算孤澎。但是如果對元素(包括所有會影響該元素的操作)啥也沒做届氢,只是取值,并不會觸發(fā)什么事情覆旭。
??

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末退子,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子型将,更是在濱河造成了極大的恐慌寂祥,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件七兜,死亡現(xiàn)場離奇詭異丸凭,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門贮乳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人恬惯,你說我怎么就攤上這事向拆。” “怎么了酪耳?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵浓恳,是天一觀的道長。 經(jīng)常有香客問我碗暗,道長颈将,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任言疗,我火速辦了婚禮晴圾,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘噪奄。我一直安慰自己死姚,他們只是感情好,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布勤篮。 她就那樣靜靜地躺著都毒,像睡著了一般。 火紅的嫁衣襯著肌膚如雪碰缔。 梳的紋絲不亂的頭發(fā)上账劲,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天,我揣著相機與錄音金抡,去河邊找鬼瀑焦。 笑死,一個胖子當著我的面吹牛梗肝,可吹牛的內(nèi)容都是我干的蝠猬。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼统捶,長吁一口氣:“原來是場噩夢啊……” “哼榆芦!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起喘鸟,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤匆绣,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后什黑,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體崎淳,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年愕把,在試婚紗的時候發(fā)現(xiàn)自己被綠了拣凹。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片森爽。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖嚣镜,靈堂內(nèi)的尸體忽然破棺而出爬迟,到底是詐尸還是另有隱情,我是刑警寧澤菊匿,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布付呕,位于F島的核電站,受9級特大地震影響跌捆,放射性物質(zhì)發(fā)生泄漏徽职。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一佩厚、第九天 我趴在偏房一處隱蔽的房頂上張望姆钉。 院中可真熱鬧,春花似錦抄瓦、人聲如沸育韩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽筋讨。三九已至,卻和暖如春摸恍,著一層夾襖步出監(jiān)牢的瞬間悉罕,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工立镶, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留壁袄,地道東北人。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓媚媒,卻偏偏與公主長得像嗜逻,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子缭召,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

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