溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

JavaScript中的事件循環(huán)機(jī)制及其運(yùn)行原理是什么

發(fā)布時(shí)間:2023-04-28 11:59:16 來源:億速云 閱讀:104 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要講解了“JavaScript中的事件循環(huán)機(jī)制及其運(yùn)行原理是什么”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“JavaScript中的事件循環(huán)機(jī)制及其運(yùn)行原理是什么”吧!

javascript是單線程的非阻塞的腳本語(yǔ)言

單線程

只有一個(gè)主線程來處理任務(wù)。

非阻塞

JS引擎執(zhí)行異步任務(wù)時(shí),不會(huì)一直等待返回結(jié)果,主線程會(huì)掛起(pending)這個(gè)任務(wù),繼續(xù)執(zhí)行其他任務(wù),當(dāng)異步任務(wù)返回結(jié)果時(shí),js將異步任務(wù)的callback放到任務(wù)隊(duì)列中,等到當(dāng)前任務(wù)棧中的任務(wù)都執(zhí)行完畢,處于閑置狀態(tài)的主線程按照隊(duì)列順序?qū)㈥?duì)首的calback函數(shù)加入到執(zhí)行棧中,執(zhí)行該函數(shù)的同步代碼,如果又遇到異步任務(wù),再將其回調(diào)函數(shù)加入到隊(duì)列中–事件循環(huán)機(jī)制。

JS通常是非阻塞的,除了某些特殊情況,JS會(huì)停止代碼執(zhí)行:alert, confirm, prompt

js的任務(wù)隊(duì)列分為同步任務(wù)和異步任務(wù)

同步任務(wù)

在主線程里執(zhí)行,當(dāng)瀏覽器第一遍過濾html文件的時(shí)候可以執(zhí)行完;(在當(dāng)前作用域直接執(zhí)行的所有內(nèi)容,包括執(zhí)行的方法、new出來的對(duì)象)

異步任務(wù)

比較耗費(fèi)時(shí)間與性能的,當(dāng)瀏覽器執(zhí)行到這些的時(shí)候會(huì)將其丟到異步任務(wù)隊(duì)列中,不會(huì)立即執(zhí)行的任務(wù)

異步任務(wù)分為宏任務(wù)(macrotask) 和 微任務(wù)(microtask),執(zhí)行的優(yōu)先級(jí)不同

宏任務(wù):script, setTimeout, setInterval, setImmeditate, T/O, UI rendering

微任務(wù):process, nextTick, promise.then(), object.observe, MutationObserver, await, async

回調(diào)函數(shù)是微任務(wù),會(huì)被加入微任務(wù)隊(duì)列,回調(diào)函數(shù)是宏任務(wù),會(huì)被加入宏任務(wù)隊(duì)列,微任務(wù)優(yōu)先級(jí)高于宏任務(wù)

Event loop過程

  • 主線程開始執(zhí)行一段代碼, 假設(shè)開始執(zhí)行一個(gè) script 標(biāo)簽內(nèi)的代碼,將代碼放入執(zhí)行棧中執(zhí)行,同步代碼優(yōu)先執(zhí)行,執(zhí)行過程中,當(dāng)遇到任務(wù)源時(shí),判斷是宏任務(wù)還是微任務(wù)。

  • 如果是宏任務(wù),加入到宏任務(wù)隊(duì)列中,如果是微任務(wù),加入到微任務(wù)隊(duì)列中。

  • 同步代碼執(zhí)行完成,執(zhí)行棧空閑,檢查微任務(wù)隊(duì)列中是否有可執(zhí)行任務(wù),如果有,依次執(zhí)行所有微任務(wù)隊(duì)列中的任務(wù)。如果沒有。當(dāng)前任務(wù)執(zhí)行結(jié)束。

  • DOM渲染。

  • 檢查宏任務(wù)隊(duì)列是否有可執(zhí)行的宏任務(wù),如果有,取出隊(duì)列中最前面的那個(gè)宏任務(wù),加入到執(zhí)行棧中開始執(zhí)行,然后重復(fù)前面步驟,直到宏任務(wù)隊(duì)列中所有任務(wù)執(zhí)行結(jié)束

微任務(wù)在DOM渲染前觸發(fā),宏任務(wù)在DOM渲染后觸發(fā)

代碼示例1

// 語(yǔ)句一
console.log(1);
// 語(yǔ)句二
setTimeout(()=>{
    console.log(2);
},0);
//語(yǔ)句三
Promise.resolve().then(()=>{
    console.log(3);
})
// 語(yǔ)句四
console.log(4);

//輸出順序
//1,4,3,2

代碼示例2

console.log("script start");
setTimeout(function () {
  console.log("setTimeout");
}, 0);
Promise.resolve()
  .then(function () {
    console.log("promise1");
  })
  .then(function () {
    console.log("promise2");
  });
console.log("script end");

JavaScript中的事件循環(huán)機(jī)制及其運(yùn)行原理是什么

代碼示例3

new Promise(…)中的代碼,也是同步代碼,會(huì)立即執(zhí)行。只有then之后的代碼,才是異步執(zhí)行的代碼

console.log("script start");
setTimeout(function () {
  console.log("timeout1");
}, 10);
new Promise((resolve) => {
  console.log("promise1");
  resolve();
  setTimeout(() => console.log("timeout2"), 10);
}).then(function () {
  console.log("then1");
});
console.log("script end");

JavaScript中的事件循環(huán)機(jī)制及其運(yùn)行原理是什么

代碼示例4

async 和 await 是 Generator 和 Promise 的語(yǔ)法糖。async 函數(shù)和普通函數(shù)一樣,只是表示這個(gè)函數(shù)里有異步操作的方法,并返回一個(gè) Promise 對(duì)象

await后面的函數(shù)執(zhí)行完畢時(shí),await會(huì)產(chǎn)生一個(gè)微任務(wù)(Promise.then是微任務(wù))。

// 等價(jià)
async function async1() {
  console.log("async1 start");
  await async2();
  console.log("async1 end");
}
// Promise 寫法
async function async1() {
  console.log("async1 start");
  Promise.resolve(async2()).then(() => console.log("async1 end"));
}

JavaScript中的事件循環(huán)機(jī)制及其運(yùn)行原理是什么

async function async1() {
  console.log("async1 start");
  await async2();
  console.log("async1 end");
}
async function async2() {
  console.log("async2");
}
async1();
setTimeout(() => {
  console.log("timeout");
}, 0);
new Promise(function (resolve) {
  console.log("promise1");
  resolve();
}).then(function () {
  console.log("promise2");
});
console.log("script end");

代碼示例5

// 1. 開始執(zhí)行
console.log(1)     // 2. 打印 1
setTimeout(function () {    // 6. 瀏覽器在 0ms 后,將該函數(shù)推入任務(wù)隊(duì)列
    console.log(2)    // 7. 打印 2
    Promise.resolve(1).then(function () {    // 8. 將 resolve(1) 推入任務(wù)隊(duì)列  9. 將 function函數(shù)推入任務(wù)隊(duì)列
        console.log('ok')    // 10. 打印 ok
    })
})    // 3.調(diào)用 setTimeout 函數(shù),并定義其完成后執(zhí)行的回調(diào)函數(shù)
setTimeout(function () {        // 11. 瀏覽器 0ms 后,將該函數(shù)推入任務(wù)隊(duì)列
    console.log(3)    // 12. 打印 3
})    // 4. 調(diào)用 setTimeout 函數(shù),并定義其完成后執(zhí)行的回調(diào)函數(shù)
// 5. 主線程執(zhí)行棧清空,開始讀取 任務(wù)隊(duì)列 中的任務(wù)
// output: 1  2 ok 3

代碼示例6

// 1. 開始執(zhí)行
console.log(1)     // 2. 打印 1
setTimeout(function () {    // 6. 瀏覽器在 0ms 后,將該函數(shù)推入任務(wù)隊(duì)列
    console.log(2)    // 7. 打印 2
    Promise.resolve(1).then(function () {    // 8. 將 resolve(1) 推入任務(wù)隊(duì)列  9. 將 function函數(shù)推入任務(wù)隊(duì)列
        console.log('ok')    // 10. 打印 ok
    })
})    // 3.調(diào)用 setTimeout 函數(shù),并定義其完成后執(zhí)行的回調(diào)函數(shù)
setTimeout(function () {        // 11. 瀏覽器 0ms 后,將該函數(shù)推入任務(wù)隊(duì)列
    console.log(3)    // 12. 打印 3
})    // 4. 調(diào)用 setTimeout 函數(shù),并定義其完成后執(zhí)行的回調(diào)函數(shù)
// 5. 主線程執(zhí)行棧清空,開始讀取 任務(wù)隊(duì)列 中的任務(wù)
// output: 1  2 ok 3

代碼示例7

setTimeout(function(){
  console.log('1')
});
new Promise(function(resolve){
  console.log('2');
  resolve();
}).then(function(){
  console.log('3')
});
var timer;
timer = setInterval(function(){
 console.log('5');
  clearInterval(timer);
});
new Promise(function(resolve){
  resolve();
}).then(function(){
  console.log('6')
});
console.log('4');
// 2,4,3,6,1,5

代碼示例8

Promise.resolve().then(()=>{
  console.log('Promise1')  
  setTimeout(()=>{
    console.log('setTimeout2')
  },0)
});
setTimeout(()=>{
  console.log('setTimeout1')
  Promise.resolve().then(()=>{
    console.log('Promise2')    
  })
},0);
console.log('start');
// start -> Promise1 -> setTimeout1 -> Promise2 - > setTimeout2

實(shí)例

<body>
  <div id="box"></div>
  <script src="./app.js"></script>s
</body>
//js
const box = document.getElementById('box')
box.innerHTML = '<P>我是后來插進(jìn)去的內(nèi)容</P>'
console.log("1");
setTimeout( ()=>{
    console.log("2");
    alert("定時(shí)器執(zhí)行了")
},0 )
Promise.resolve().then(()=>{
    console.log("3")
    alert("Promise執(zhí)行了")
})
console.log("4");

JavaScript中的事件循環(huán)機(jī)制及其運(yùn)行原理是什么

tip:從規(guī)范來看,microtask (微任務(wù))優(yōu)先于 macrotask(宏任務(wù)) 執(zhí)行,所以如果有需要優(yōu)先執(zhí)行的邏輯,放入microtask 隊(duì)列會(huì)比 task 更早的被執(zhí)行。

感謝各位的閱讀,以上就是“JavaScript中的事件循環(huán)機(jī)制及其運(yùn)行原理是什么”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對(duì)JavaScript中的事件循環(huán)機(jī)制及其運(yùn)行原理是什么這一問題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI