溫馨提示×

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

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

JavaScript事件循環(huán)怎么使用

發(fā)布時(shí)間:2023-04-19 14:18:13 來(lái)源:億速云 閱讀:85 作者:iii 欄目:開發(fā)技術(shù)

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

JavaScript事件循環(huán)是一種機(jī)制,用于處理異步事件和回調(diào)函數(shù)。它是JavaScript運(yùn)行時(shí)環(huán)境的一部分,負(fù)責(zé)管理事件隊(duì)列和調(diào)用棧。

事件循環(huán)的基本原理是事件循環(huán)的核心是一個(gè)事件隊(duì)列,所有的事件都被放入這個(gè)隊(duì)列中,然后按照順序依次執(zhí)行。如果隊(duì)列為空,JavaScript會(huì)等待新的任務(wù)加入隊(duì)列。當(dāng)JavaScript代碼執(zhí)行時(shí),所有同步任務(wù)都會(huì)被立即執(zhí)行,而異步任務(wù)則會(huì)被放入事件隊(duì)列中。

當(dāng)所有同步任務(wù)執(zhí)行完畢后,事件循環(huán)會(huì)從事件隊(duì)列中取出一個(gè)任務(wù),并將其放入調(diào)用棧中執(zhí)行。當(dāng)該任務(wù)執(zhí)行完畢后,事件循環(huán)會(huì)再次從事件隊(duì)列中取出下一個(gè)任務(wù),并重復(fù)這個(gè)過(guò)程。

一、事件循環(huán)的執(zhí)行過(guò)程

1、執(zhí)行同步代碼,直到遇到第一個(gè)異步事件(如setTimeout、setInterval、Promise等)。

2、將異步事件放入事件隊(duì)列中,并繼續(xù)執(zhí)行同步代碼。

3、當(dāng)所有同步代碼執(zhí)行完畢后,JavaScript引擎會(huì)檢查事件隊(duì)列中是否有事件需要執(zhí)行。

4、如果事件隊(duì)列中有事件需要執(zhí)行,JavaScript引擎會(huì)將第一個(gè)事件取出來(lái),并執(zhí)行對(duì)應(yīng)的回調(diào)函數(shù)。

5、執(zhí)行完回調(diào)函數(shù)后,JavaScript引擎會(huì)再次檢查事件隊(duì)列中是否有事件需要執(zhí)行,如果有則重復(fù)步驟4,否則繼續(xù)等待新的事件加入事件隊(duì)列。

需要注意的是,事件循環(huán)是單線程的,也就是說(shuō)JavaScript引擎在同一時(shí)間只能執(zhí)行一個(gè)任務(wù)。

因此,如果一個(gè)任務(wù)執(zhí)行時(shí)間過(guò)長(zhǎng),會(huì)阻塞事件循環(huán),導(dǎo)致其他任務(wù)無(wú)法執(zhí)行。為了避免這種情況,可以將長(zhǎng)時(shí)間的任務(wù)拆分成多個(gè)小任務(wù),使用setTimeout或setInterval分批執(zhí)行。

另外,Promise也是基于事件循環(huán)的機(jī)制實(shí)現(xiàn)的。當(dāng)Promise狀態(tài)發(fā)生改變時(shí),會(huì)將對(duì)應(yīng)的回調(diào)函數(shù)放入微任務(wù)隊(duì)列中,等待當(dāng)前任務(wù)執(zhí)行完畢后立即執(zhí)行。因此,Promise的回調(diào)函數(shù)總是在當(dāng)前任務(wù)執(zhí)行完畢后立即執(zhí)行,而不會(huì)被放入事件隊(duì)列中等待執(zhí)行。

二、事件循環(huán)進(jìn)階用法

1、Promise:Promise是一種異步編程的解決方案,它可以將異步操作轉(zhuǎn)化為同步操作的形式,使得代碼更加簡(jiǎn)潔易懂。Promise的基本原理是將異步操作封裝成一個(gè)Promise對(duì)象,通過(guò)then方法來(lái)處理異步操作的結(jié)果。

2、async/await:async/await是ES2017引入的一種異步編程的解決方案,它可以讓異步代碼看起來(lái)像同步代碼,使得代碼更加易讀易懂。async/await的基本原理是使用async關(guān)鍵字定義一個(gè)異步函數(shù),然后在函數(shù)內(nèi)部使用await關(guān)鍵字來(lái)等待異步操作的結(jié)果。

3、定時(shí)器:JavaScript中有兩種定時(shí)器,分別是setTimeout和setInterval。setTimeout用于在指定的時(shí)間后執(zhí)行一次任務(wù),而setInterval則用于每隔一段時(shí)間執(zhí)行一次任務(wù)。這兩種定時(shí)器都是異步任務(wù),會(huì)被放入任務(wù)隊(duì)列中等待執(zhí)行。

三、JavaScript任務(wù)類型

JavaScript中的任務(wù)按照不同緯度進(jìn)行區(qū)分主要分為同步任務(wù)和異步任務(wù)、宏任務(wù)和微任務(wù)。

3.1 同步任務(wù)&異步任務(wù)

1、 同步任務(wù)按照代碼順序執(zhí)行的任務(wù)。

2、 異步任務(wù)是在將來(lái)某個(gè)時(shí)間點(diǎn)執(zhí)行的任務(wù)。異步任務(wù)通常是由事件觸發(fā)器(如鼠標(biāo)點(diǎn)擊、網(wǎng)絡(luò)請(qǐng)求等)生成的。 當(dāng)一個(gè)異步任務(wù)被觸發(fā)時(shí),它會(huì)被放入任務(wù)隊(duì)列中等待執(zhí)行。

JavaScript事件循環(huán)的執(zhí)行順序可以用以下偽代碼表示:

while (queue.waitForMessage()) { 
    queue.processNextMessage(); 
}

在這個(gè)偽代碼中,queue.waitForMessage()表示等待隊(duì)列中有待執(zhí)行的任務(wù),queue.processNextMessage()表示取出隊(duì)列中的下一個(gè)任務(wù)并執(zhí)行。

需要注意的是,JavaScript事件循環(huán)的執(zhí)行順序是不可中斷的。這意味著當(dāng)一個(gè)任務(wù)正在執(zhí)行時(shí),其他任務(wù)必須等待,直到當(dāng)前任務(wù)完成。因此,如果一個(gè)任務(wù)執(zhí)行時(shí)間過(guò)長(zhǎng),會(huì)導(dǎo)致其他任務(wù)無(wú)法及時(shí)執(zhí)行,從而影響應(yīng)用程序的性能和響應(yīng)速度。

3.2 宏任務(wù)&微任務(wù)

1、宏任務(wù)包括setTimeout、setInterval、I/O操作等。

2、微任務(wù)包括Promise、MutationObserver等。

當(dāng)事件循環(huán)從事件隊(duì)列中取出一個(gè)任務(wù)時(shí),它會(huì)先執(zhí)行所有微任務(wù),然后再執(zhí)行一個(gè)宏任務(wù)。這個(gè)過(guò)程會(huì)一直重復(fù),直到事件隊(duì)列中的所有任務(wù)都被執(zhí)行完畢。

下面是一個(gè)例子:

console.log('1'); 

setTimeout(function() { 
    console.log('2'); 
    Promise.resolve().then(function() { 
        console.log('3'); 
    }); 
}, 0); 

Promise.resolve().then(function() { 
    console.log('4'); 
}); 
console.log('5'); 

// 輸出結(jié)果為: 1 5 4 2 3

執(zhí)行順序:

  • 執(zhí)行第一個(gè)console.log,輸出1。

  • 執(zhí)行setTimeout,將其回調(diào)函數(shù)放入宏任務(wù)隊(duì)列中。

  • 執(zhí)行Promise.resolve().then,將其回調(diào)函數(shù)放入微任務(wù)隊(duì)列中。

  • 執(zhí)行第二個(gè)console.log,輸出5。

  • 當(dāng)前任務(wù)執(zhí)行結(jié)束,執(zhí)行微任務(wù)隊(duì)列中的所有任務(wù),輸出4。

  • 執(zhí)行宏任務(wù)隊(duì)列中的第一個(gè)任務(wù),即setTimeout的回調(diào)函數(shù),輸出2。

  • 執(zhí)行Promise.resolve().then的回調(diào)函數(shù),輸出3。

需要注意的是,微任務(wù)和宏任務(wù)的執(zhí)行順序是固定的,即先執(zhí)行所有微任務(wù),再執(zhí)行宏任務(wù)。因此,如果在一個(gè)宏任務(wù)中產(chǎn)生了新的微任務(wù),那么這些微任務(wù)會(huì)在下一個(gè)宏任務(wù)執(zhí)行之前執(zhí)行。

下面是一個(gè)例子:

console.log('1'); 

setTimeout(function() { 
    console.log('2'); 
    Promise.resolve().then(function() { 
        console.log('3'); 
    }); 
}, 0); 

Promise.resolve().then(function() { 
    console.log('4'); 
    setTimeout(function() { 
        console.log('5'); 
    }, 0); 
}); 

console.log('6'); 

// 輸出結(jié)果為:1 6 4 2 3 5

執(zhí)行順序:

  • 執(zhí)行第一個(gè)console.log,輸出1。

  • 執(zhí)行setTimeout,將其回調(diào)函數(shù)放入宏任務(wù)隊(duì)列中。

  • 執(zhí)行Promise.resolve().then,將其回調(diào)函數(shù)放入微任務(wù)隊(duì)列中。

  • 執(zhí)行第三個(gè)console.log,輸出6。

  • 當(dāng)前任務(wù)執(zhí)行結(jié)束,執(zhí)行微任務(wù)隊(duì)列中的所有任務(wù),輸出4。

  • 執(zhí)行宏任務(wù)隊(duì)列中的第一個(gè)任務(wù),即setTimeout的回調(diào)函數(shù),輸出2。

  • 執(zhí)行Promise.resolve().then的回調(diào)函數(shù),將setTimeout的回調(diào)函數(shù)放入宏任務(wù)隊(duì)列中。

  • 當(dāng)前任務(wù)執(zhí)行結(jié)束,執(zhí)行微任務(wù)隊(duì)列中的所有任務(wù),輸出3。

  • 執(zhí)行宏任務(wù)隊(duì)列中的第一個(gè)任務(wù),即setTimeout的回調(diào)函數(shù),輸出5。

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

向AI問(wèn)一下細(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