js的事件循環(huán),宏任務(wù)與微任務(wù)

本人一開始對于JS的執(zhí)行機制了解很模糊,通過查找好多大牛資料總結(jié)了一下,終于理解通透了,希望我的文章能幫助到你喲,閱讀期間有各種疑問歡迎@我,咱們一起探討成長??!

事件循環(huán)

JS是單線程執(zhí)行的,JS執(zhí)行時基于一種事件循環(huán)的機制,形成了基本沒有阻塞(除了alert或同步XHR等操作)的狀態(tài)。
JS的運行環(huán)境主要有瀏覽器,Node。根據(jù)JS在瀏覽器中運行規(guī)范,每個線程都有事件循環(huán)(Event Loop)。
JS在執(zhí)行任務(wù)時,所有任務(wù)可以分為兩種 ,一種是同步任務(wù),另一種是異步任務(wù)。 同步任務(wù)指在主線程上排隊執(zhí)行的任務(wù),只有前一個任務(wù)執(zhí)行完畢,才能執(zhí)行后一個任務(wù);異步任務(wù)指的是,不進入主線程,而進入‘任務(wù)隊列’的任務(wù),只有‘任務(wù)隊列’通知主線程,某個異步任務(wù)可以執(zhí)行了,該任務(wù)才會進入主線程執(zhí)行。
任務(wù)有同步任務(wù),異步任務(wù)。而異步任務(wù)又分為宏任務(wù)和微任務(wù)
簡單的說:js執(zhí)行任務(wù)的順序 主線程--微任務(wù)--渲染--宏任務(wù)。此過程會不斷重復,這個過程就叫事件循環(huán))

常見異步任務(wù)類型

settimeout的回調(diào)函數(shù)放到宏任務(wù)隊列里,等到執(zhí)行棧清空以后執(zhí)行
promise本身是同步的立即執(zhí)行函數(shù)(同步)
promise.then里的回調(diào)函數(shù)會放到相應(yīng)宏任務(wù)的微任務(wù)隊列里,等宏任務(wù)里面的同步代碼執(zhí)行完再執(zhí)行;
async函數(shù)表示函數(shù)里面可能會有異步方法,await后面跟一個表達式,async方法執(zhí)行時,遇到await會立即執(zhí)行表達式,然后把await表達式后面的代碼放到微任務(wù)隊列里,讓出執(zhí)行棧讓同步代碼先執(zhí)行

宏任務(wù)和微任務(wù)

宏任務(wù)(macro-task)

可以理解成:每次執(zhí)行棧的代碼就是一個宏任務(wù)(包括每次從事件隊列中獲取的一個事件回調(diào)并放到執(zhí)行中執(zhí)行)。
瀏覽器為了能夠使得 JS 內(nèi)部 macro-task 與 DOM 任務(wù)有序地執(zhí)行,會在宏任務(wù)執(zhí)行結(jié)束之后,在下一個宏任務(wù)開始執(zhí)行之前,對頁面進行重新渲染。

macro-task -> render -> macro-task -> ...
宏任務(wù)包括:
script全部代碼
setInterval
setTimeout
setImmediate(node.js)
XHR 回調(diào)
事件回調(diào)(鼠標鍵盤事件)
indexedDB 數(shù)據(jù)庫等 I/O 操作
UI rendering

微任務(wù)(micro-task)

可以理解成:當前 macro-task執(zhí)行結(jié)束之后立即執(zhí)行的任務(wù)。(在下一個 macro-task 之前 ,在渲染之前)

macro-task -> micro-task -> render -> macro-task -> ...
微任務(wù)包括:
Promise.then catch finally
async, await
process.nextTick(node.js)
MutationObserver
Object.observe(已被棄用)

宏任務(wù)與微任務(wù)執(zhí)行順序:

執(zhí)行棧在執(zhí)行完同步任務(wù)后,查看執(zhí)行棧是否為空,如果執(zhí)行棧為空,就會去檢查微任務(wù)隊列是否為空,如果為空的話,就執(zhí)行宏任務(wù),否則就一次性執(zhí)行完所有微任務(wù)。

每次單個宏任務(wù)執(zhí)行完畢后,檢查微任務(wù)隊列是否為空,如果不為空的話,會按照先入先出的規(guī)則全部執(zhí)行完微任務(wù)后,設(shè)置微任務(wù)隊列為null,然后再執(zhí)行宏任務(wù),如此循環(huán)。

總結(jié):同步—>微任務(wù)—>宏任務(wù)

例子
console.log('ok')
new Promise(function(resolve){
    console.log('1');
    resolve();
}).then(function(){
    console.log('2')
});

setTimeout(function(){
    console.log('3')
});

console.log('4');
//ok,1,4,2,3
console.log(1)
process.nextTick(() => { // 微任務(wù)
  console.log(8)
  setTimeout(() => {
    console.log(9)
  })
})
setTimeout(() => { // 宏任務(wù)
  console.log(2)
  new Promise(() => {
    console.log(11)
  })
})
// 特殊說明: new Promise()屬于主線程任務(wù)
let promise = new Promise((resolve,reject) => {
  setTimeout(() => {
    console.log(10)
  })
  resolve()
  // 這個console也屬于主線程任務(wù)
  console.log(4)
})
fn()
console.log(3)
promise.then(() => { //微任務(wù)
  console.log(12)
})
function fn(){
  console.log(6)
}
結(jié)果是1、4、6、3、12、8、2、11、10、9

案例參考https://www.cnblogs.com/yalong/p/10369477.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容