|
導(dǎo)讀網(wǎng)頁(yè)的本質(zhì)就是超級(jí)文本標(biāo)記語(yǔ)言,通過結(jié)合使用其他的Web技術(shù)(如:腳本語(yǔ)言、公共網(wǎng)關(guān)接口、組件等),可以創(chuàng)造出功能強(qiáng)大的網(wǎng)頁(yè)。因而,超級(jí)文本標(biāo)記語(yǔ)言是萬(wàn)維網(wǎng)(Web)編程的基礎(chǔ),也就是說(shuō)萬(wàn)維網(wǎng)是建立... 網(wǎng)頁(yè)的本質(zhì)就是超級(jí)文本標(biāo)記語(yǔ)言,通過結(jié)合使用其他的Web技術(shù)(如:腳本語(yǔ)言、公共網(wǎng)關(guān)接口、組件等),可以創(chuàng)造出功能強(qiáng)大的網(wǎng)頁(yè)。因而,超級(jí)文本標(biāo)記語(yǔ)言是萬(wàn)維網(wǎng)(Web)編程的基礎(chǔ),也就是說(shuō)萬(wàn)維網(wǎng)是建立在超文本基礎(chǔ)之上的。超級(jí)文本標(biāo)記語(yǔ)言之所以稱為超文本標(biāo)記語(yǔ)言,是因?yàn)槲谋局邪怂^“超級(jí)鏈接”點(diǎn)。 本篇文章給大家?guī)?lái)的內(nèi)容是關(guān)于瀏覽器事件循環(huán)的深入了解(代碼示例),有一定的參考價(jià)值,有需要的朋友可以參考一下,希望對(duì)你有所幫助。瀏覽器的事件循環(huán),前端再熟悉不過了,每天都會(huì)接觸的東西。但我以前一直都是死記硬背:事件任務(wù)隊(duì)列分為macrotask和microtask,瀏覽器先從macrotask取出一個(gè)任務(wù)執(zhí)行,再執(zhí)行microtask內(nèi)的所有任務(wù),接著又去macrotask取出一個(gè)任務(wù)執(zhí)行...,這樣一直循環(huán)下去。但是對(duì)于下面的代碼,我一直懵逼,setTimeout屬于macrotask,按照上面的規(guī)則,setTimeout應(yīng)該先被取出來(lái)執(zhí)行啊,但是我卻被執(zhí)行結(jié)果打臉了。 <script>
setTimeout(() => {
console.log(1)
}, 0)
new Promise((resolve) => {
console.log(2)
resolve()
}).then(() => {
console.log(3)
})
// 我曾經(jīng)的預(yù)期是:2 1 3
// 實(shí)際輸出:2 3 1
</script>經(jīng)過再仔細(xì)看別人對(duì)任務(wù)隊(duì)列的介紹,才知道,同步執(zhí)行的js代碼其實(shí)就算一個(gè)macrotask(準(zhǔn)確說(shuō)是每一個(gè)script標(biāo)簽內(nèi)的代碼都是一個(gè)macrotask),所以上面的規(guī)則中說(shuō)的 先取出一個(gè)macrotask執(zhí)行 是沒有問題的。 macrotask的本質(zhì)macrotask本質(zhì)上是瀏覽器多個(gè)線程之間通信的一個(gè)消息隊(duì)列 瀏覽器的各種線程都是常駐線程,它們運(yùn)行在一個(gè)for死循環(huán)里面,每個(gè)線程都有屬于自己的若干任務(wù)隊(duì)列,線程自己或者其它線程都可能通過PostTask向這些任務(wù)隊(duì)列添加任務(wù),這些線程會(huì)不斷地從自己的任務(wù)隊(duì)列中取出任務(wù)執(zhí)行,或者是處于睡眠狀態(tài)直到設(shè)定的時(shí)間或者是有人PostTask的時(shí)候把它們喚醒。 可以簡(jiǎn)單地理解為,瀏覽器的各個(gè)線程都在不停地從自己的任務(wù)隊(duì)列中取出任務(wù),執(zhí)行,再取出任務(wù),再執(zhí)行,這樣無(wú)限循環(huán)下去。 以下面的代碼為例: <script>
console.log(1)
setTimeout(() => {
console.log(2)
}, 1000)
console.log(3)
</script>
可以看到,所謂的macrotask并不是瀏覽器定義了哪些任務(wù)是macrotask,瀏覽器各個(gè)線程只是忠實(shí)地循環(huán)自己的任務(wù)隊(duì)列,不停地執(zhí)行其中的任務(wù)而已。 microtask比起macrotask是瀏覽器的多線程模型造成的“假象”,microtask是確實(shí)存在的一個(gè)隊(duì)列,microtask是屬于當(dāng)前線程的,而不是其他線程PostTask過來(lái)的任務(wù),只是延遲執(zhí)行了而已(準(zhǔn)確地說(shuō)是放到了當(dāng)前執(zhí)行的同步代碼之后執(zhí)行),比如Promise.then、MutationObserver都屬于這種情況。 以下面的代碼為例: <script>
new Promise((resolve) => {
resolve()
console.log(1)
setTimeout(() => {
console.log(2)
},0)
}).then(() => {
console.log(3)
})
// 輸出:1 3 2
</script>
總結(jié)通過上面的分析,可以看到,文章開頭提到的規(guī)則:瀏覽器先從macrotask取出一個(gè)任務(wù)執(zhí)行,再執(zhí)行microtask內(nèi)的所有任務(wù),接著又去macrotask取出一個(gè)任務(wù)執(zhí)行...,并沒有說(shuō)錯(cuò),但這只是瀏覽器執(zhí)行機(jī)制造成的現(xiàn)象,而不是說(shuō)瀏覽器按照這樣的規(guī)則去執(zhí)行的代碼。 console.log('start')
const interval = setInterval(() => {
console.log('setInterval')
}, 0)
setTimeout(() => {
console.log('setTimeout 1')
Promise.resolve()
.then(() => {
console.log('promise 3')
})
.then(() => {
console.log('promise 4')
})
.then(() => {
setTimeout(() => {
console.log('setTimeout 2')
Promise.resolve()
.then(() => {
console.log('promise 5')
})
.then(() => {
console.log('promise 6')
})
.then(() => {
clearInterval(interval)
})
}, 0)
})
}, 0)
Promise.resolve()
.then(() => {
console.log('promise 1')
})
.then(() => {
console.log('promise 2')
})
// 執(zhí)行結(jié)果
/* start
promise 1
promise 2
setInterval
setTimeout 1
promise 3
promise 4
setInterval
setTimeout 2
promise 5
promise 6
*/以上就是瀏覽器事件循環(huán)的深入了解(代碼示例)的詳細(xì)內(nèi)容,更多請(qǐng)關(guān)注php中文網(wǎng)其它相關(guān)文章! 網(wǎng)站建設(shè)是一個(gè)廣義的術(shù)語(yǔ),涵蓋了許多不同的技能和學(xué)科中所使用的生產(chǎn)和維護(hù)的網(wǎng)站。 |
溫馨提示:喜歡本站的話,請(qǐng)收藏一下本站!