JS內(nèi)部事件機(jī)制之單線程原理
任務(wù)隊(duì)列
主線程:正在執(zhí)行的代碼,會(huì)生成函數(shù)調(diào)用棧。
- macro-task(宏任務(wù),新名:task)包括:script(整體代碼), setTimeout, setInterval, setImmediate, I/O, UI rendering。
- micro-task(微任務(wù),新名:jobs)包括: process.nextTick, Promise, Object.observe(已廢棄), MutationObserver(html5新特性,隊(duì)列中只能有一個(gè))
任務(wù)分類
同步任務(wù),語(yǔ)句只按語(yǔ)句先后順序執(zhí)行,前面未執(zhí)行完,不會(huì)執(zhí)行后面語(yǔ)句。
異步任務(wù),語(yǔ)句不在語(yǔ)句先后順序上執(zhí)行,執(zhí)行到該代碼時(shí),加入到相應(yīng)任務(wù)隊(duì)列,延后執(zhí)行。
單線程
主線程從 script (整體代碼)開始第一次循環(huán)。之后全局上下文進(jìn)入函數(shù)調(diào)用棧。直到調(diào)用棧清空(只剩全局),然后執(zhí)行所有的 jobs。當(dāng)所有可執(zhí)行的 jobs 執(zhí)行完畢之后。循環(huán)再次從 task 開始,找到其中一個(gè)任務(wù)隊(duì)列執(zhí)行完畢,然后再執(zhí)行所有的 jobs,這樣一直循環(huán)下去。
注意事項(xiàng)
- setTimeout 最小間隔不能低于 4 毫秒,否則會(huì)自動(dòng)增加。
- DOM 的渲染每 16 毫秒執(zhí)行一次,因?yàn)轱@示器是 60 Hz,16ms 刷新一次。
- process.nextTick 任務(wù)會(huì)在 jobs 里單獨(dú)維護(hù)一個(gè)隊(duì)列,并且在其他 jobs 任務(wù)之前執(zhí)行。
- 冒泡事件會(huì)直接在子元素事件執(zhí)行完成后,插入在主線程中。如果主線程不為空,那么會(huì)優(yōu)先于 jobs 執(zhí)行。
經(jīng)典示例
示例詳解:https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/
通過(guò)鼠標(biāo)點(diǎn)擊
<div class="outer"> <div class="inner"></div> </div> // Let's get hold of those elements var outer = document.querySelector('.outer'); var inner = document.querySelector('.inner'); // Let's listen for attribute changes on the // outer element new MutationObserver(function() { console.log('mutate'); }).observe(outer, { attributes: true }); // Here's a click listener… function onClick() { console.log('click'); setTimeout(function() { console.log('timeout'); }, 0); Promise.resolve().then(function() { console.log('promise'); }); outer.setAttribute('data-random', Math.random()); } // …which we'll attach to both elements inner.addEventListener('click', onClick); outer.addEventListener('click', onClick); // 輸出結(jié)果 click mutate click mutate promise promise timeout timeout
進(jìn)階--通過(guò)js執(zhí)行
<div class="outer"> <div class="inner"></div> </div> // Let's get hold of those elements var outer = document.querySelector('.outer'); var inner = document.querySelector('.inner'); // Let's listen for attribute changes on the // outer element new MutationObserver(function() { console.log('mutate'); }).observe(outer, { attributes: true }); // Here's a click listener… function onClick() { console.log('click'); setTimeout(function() { console.log('timeout'); }, 0); Promise.resolve().then(function() { console.log('promise'); }); outer.setAttribute('data-random', Math.random()); } // …which we'll attach to both elements inner.addEventListener('click', onClick); outer.addEventListener('click', onClick); inner.click(); // 輸出結(jié)果 click click mutate promise promise timeout timeout
由于點(diǎn)擊事件是 js 執(zhí)行的,inner 的 onClick 函數(shù)執(zhí)行完成時(shí),inner.click() 語(yǔ)句的作用域還沒(méi)有退棧,主線程調(diào)用棧不是空的,導(dǎo)致 jobs 隊(duì)列任務(wù)不會(huì)執(zhí)行,mutate 和 promise 語(yǔ)句都未能在事件循環(huán)中執(zhí)行到。從而執(zhí)行了 outer 的 onClick 函數(shù)。outer 的 onClick 函數(shù)執(zhí)行完成后,inner.click() 語(yǔ)句才退棧,繼而執(zhí)行 jobs 的任務(wù)。
只有一個(gè) mutate 是由于 jobs 隊(duì)列中,只能有一個(gè) MutationObserver 任務(wù),第二次創(chuàng)建時(shí),前一個(gè) MutationObserver 任務(wù)沒(méi)有執(zhí)行,顧不再創(chuàng)建。
總結(jié)
以上所述是小編給大家介紹的JS內(nèi)部事件機(jī)制之單線程原理,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
相關(guān)文章
JavaScript中附件預(yù)覽功能實(shí)現(xiàn)詳解(推薦)
這篇文章主要介紹了JavaScript中附件預(yù)覽功能的實(shí)現(xiàn),具體操作步驟大家可查看下文詳細(xì)講解,感興趣的小伙伴們可以參考一下。2017-08-08JavaScript中Object基礎(chǔ)內(nèi)部方法圖
本篇文章通過(guò)一張?jiān)敿?xì)的JavaScript中Object基礎(chǔ)內(nèi)部方法圖介紹了其基本用法,需要的朋友參考下。2018-02-02詳談JS中實(shí)現(xiàn)種子隨機(jī)數(shù)及作用
這篇文章詳細(xì)介紹了種子隨機(jī)數(shù)在JS中如何實(shí)現(xiàn)以及有什么作用,希望能幫助有需要的人。下面一起來(lái)看看。2016-07-07基于JS對(duì)象創(chuàng)建常用方式及原理分析
下面小編就為大家?guī)?lái)一篇基于JS對(duì)象創(chuàng)建常用方式及原理分析。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-06-06微信小程序Page中data數(shù)據(jù)操作和函數(shù)調(diào)用方法
這篇文章主要介紹了微信小程序Page中data數(shù)據(jù)操作和函數(shù)調(diào)用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05JS window對(duì)象簡(jiǎn)單操作完整示例
這篇文章主要介紹了JS window對(duì)象簡(jiǎn)單操作,結(jié)合完整實(shí)例形式分析了JavaScript Window對(duì)象各種常見提示框、彈出窗口及時(shí)間相關(guān)操作技巧,需要的朋友可以參考下2020-01-01詳解JavaScript原生封裝ajax請(qǐng)求和Jquery中的ajax請(qǐng)求
在本篇文章中我們總結(jié)了關(guān)于JavaScript原生封裝ajax請(qǐng)求和Jquery中的ajax請(qǐng)求的知識(shí)點(diǎn)內(nèi)容,需要的朋友們學(xué)習(xí)參考下。2019-02-02