成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

淺談不同環(huán)境下的JavaScript執(zhí)行機(jī)制 + 示例詳解

wanghui / 2819人閱讀

摘要:如果沒有其他異步任務(wù)要處理比如到期的定時(shí)器,會(huì)一直停留在這個(gè)階段,等待請(qǐng)求返回結(jié)果。執(zhí)行的執(zhí)行事件關(guān)閉請(qǐng)求的,例如事件循環(huán)的每一次循環(huán)都需要依次經(jīng)過上述的階段。因此,才會(huì)早于執(zhí)行。

概念 同步任務(wù)(Synchronous)

在主線程上排隊(duì)執(zhí)行的任務(wù),只有前一個(gè)任務(wù)執(zhí)行完畢,才能執(zhí)行后一個(gè)任務(wù)

異步任務(wù)(Asynchronous)

不進(jìn)入主線程,而是進(jìn)入“任務(wù)隊(duì)列”的任務(wù),只有主線執(zhí)行棧清空,異步任務(wù)才進(jìn)入主線執(zhí)行棧執(zhí)行

任務(wù)隊(duì)列(Task Queue)

包含有異步任務(wù)的隊(duì)列,包括“宏任務(wù)”與“微任務(wù)”

宏任務(wù)(Macrotasks / Task)

創(chuàng)建文檔對(duì)象、解析 HTML、執(zhí)行主線程代碼(script)

執(zhí)行各種事件:頁面加載、輸入、點(diǎn)擊

setTimout,setInterval,setImmediate

I/O,Ajax,UI rendering

微任務(wù)(Microtasks / Jobs)

process.nextTick

Promise.then

Object.observe(已廢棄)

MutationObserver

事件循環(huán)(Event Loop)
瀏覽器下的事件循環(huán)

事件循環(huán)是js實(shí)現(xiàn)異步的一種方法,也是js的執(zhí)行機(jī)制

JavaScript 主線程會(huì)在執(zhí)行棧清空后,讀取任務(wù)隊(duì)列,入棧第一個(gè)宏任務(wù),主線程執(zhí)行完該任務(wù)后又會(huì)先檢查微任務(wù)隊(duì)列并完成里面的所有微任務(wù),包括新創(chuàng)建的微任務(wù),完成一次事件循環(huán)。之后再次去讀取任務(wù)隊(duì)列,不斷循環(huán)

注意:

每次循環(huán)只會(huì)入棧一個(gè)宏任務(wù),所以多個(gè)宏任務(wù)需要多次事件循環(huán)才能執(zhí)行完

每次循環(huán)會(huì)執(zhí)行所有的微任務(wù),所以每次循環(huán)結(jié)束后微任務(wù)隊(duì)列被清空

Node.JS下的事件循環(huán)

timers

執(zhí)行 setTimeoutsetInterval 中到期的 callback

I/O callbacks

除了以下操作的回調(diào)函數(shù),其他的回調(diào)函數(shù)都在這個(gè)階段執(zhí)行。

setTimeoutsetInterval,setImmediatecallback

用于執(zhí)行 close 事件(關(guān)閉請(qǐng)求)的 callback,例如 socket.on("close", callback)

idle, prepare

libuv 內(nèi)部調(diào)用

poll

最為重要的階段,用于等待還未返回的 I/O 事件,比如服務(wù)器的回應(yīng)、用戶移動(dòng)鼠標(biāo)等等

這個(gè)階段的時(shí)間會(huì)比較長。如果沒有其他異步任務(wù)要處理(比如到期的定時(shí)器),會(huì)一直停留在這個(gè)階段,等待 I/O 請(qǐng)求返回結(jié)果。

check

執(zhí)行 setImmediatecallback

close callbacks

執(zhí)行 close 事件(關(guān)閉請(qǐng)求)的 callback,例如 socket.on("close", callback)

事件循環(huán)的每一次循環(huán)都需要依次經(jīng)過上述的階段。 每個(gè)階段都有自己的 callback 隊(duì)列,每當(dāng)進(jìn)入某個(gè)階段,都會(huì)從所屬的隊(duì)列中取出callback來執(zhí)行,當(dāng)隊(duì)列為空或者被執(zhí)行callback的數(shù)量達(dá)到系統(tǒng)的最大數(shù)量時(shí),進(jìn)入下一階段。這六個(gè)階段都執(zhí)行完畢稱為一輪循環(huán)

注意:

不同于瀏覽器的是,在每個(gè)階段完成后,microTask隊(duì)列就會(huì)被執(zhí)行,而不是MacroTask任務(wù)完成后。

每個(gè)階段完成后,微任務(wù)隊(duì)列就會(huì)被執(zhí)行。

如果在timers階段執(zhí)行時(shí)創(chuàng)建了setImmediate則會(huì)在此輪循環(huán)的check階段執(zhí)行,如果在timers階段創(chuàng)建了 setTimeout,由于timers已取出完畢,則會(huì)進(jìn)入下輪循環(huán),check階段創(chuàng)建timers任務(wù)同理

遞歸的調(diào)用 process.nextTick 會(huì)導(dǎo)致 I/O starving,官方推薦使用 setImmediate

Node.JS與瀏覽器下的差異

瀏覽器環(huán)境下,microtask 的任務(wù)隊(duì)列是每個(gè) macrotask 執(zhí)行完之后執(zhí)行

Node.js中,microtask 會(huì)在事件循環(huán)的各個(gè)階段之間執(zhí)行,也就是一個(gè)階段執(zhí)行完畢,就會(huì)去執(zhí)行 microtask 隊(duì)列的任務(wù)

setTimeout(()=>{
    console.log("timer1")

    Promise.resolve().then(function() {
        console.log("promise1")
    })
}, 0)

setTimeout(()=>{
    console.log("timer2")

    Promise.resolve().then(function() {
        console.log("promise2")
    })
}, 0)

// 瀏覽器輸出:
// time1
// promise1
// time2
// promise2

// Node輸出:
// time1
// time2
// promise1
// promise2
定時(shí)器 setTimeout(callback, time)

經(jīng)過指定時(shí)間后,把要執(zhí)行的任務(wù) callback 加入到任務(wù)隊(duì)列中

因?yàn)镴S是單線程,任務(wù)要一個(gè)一個(gè)執(zhí)行,如果前面的任務(wù)需要的時(shí)間太久,那么只能等著,導(dǎo)致真正的延遲時(shí)間可能遠(yuǎn)遠(yuǎn)大于指定時(shí)間(time ms)

setTimeout(callback, 0)

指定某個(gè)任務(wù) callback 在主線程最早可得的空閑時(shí)間執(zhí)行,意思就是不用再等多少秒了,只要主線程執(zhí)行棧內(nèi)的同步任務(wù)全部執(zhí)行完成,棧為空就馬上執(zhí)行

0ms 實(shí)際上是不可能的,在瀏覽器中 setTimeout() / setInterval() 的每調(diào)用一次定時(shí)器的最小間隔 >=4ms,這通常是由于函數(shù)嵌套導(dǎo)致(嵌套層級(jí)達(dá)到一定深度),或者是由于已經(jīng)執(zhí)行的 setInterval 的回調(diào)函數(shù)阻塞導(dǎo)致的

在 Node.JS 環(huán)境為 1ms,但也取決于系統(tǒng)當(dāng)時(shí)的狀況

setTimeout(function () {
    console.log("1");
}, 0)

console.log(2)

// 輸出 2 1
setInterval(callback, time)

每過指定時(shí)間(time ms),會(huì)有 callback 進(jìn)入任務(wù)隊(duì)列。

callback 執(zhí)行時(shí)間超過了指定時(shí)間,那么就會(huì)導(dǎo)致 callback 連續(xù)執(zhí)行,完全看不出來有時(shí)間間隔了

setImmediate(callback)

Node.JS 特有定時(shí)器,在事件循環(huán)的 check 階段執(zhí)行

process.nextTick(callback)

Node.JS 特有定時(shí)器,在事件循環(huán)各個(gè)階段結(jié)束后執(zhí)行

從技術(shù)上講,它不是事件循環(huán)的一部分

同循環(huán)下 process.nextTick 會(huì)優(yōu)于 Promise.then

Promise.resolve().then(() => console.log(1));
process.nextTick(() => console.log(2));

// 輸出 2 1
注意

連續(xù)的 setTimeout,setImmediate 在再 timer 階段的執(zhí)行順序是不確定的,取決于系統(tǒng)當(dāng)時(shí)的狀況

但是把 setTimeout,setImmediate 放到一個(gè) I/O 回調(diào)里面,就一定是 setImmediate 先執(zhí)行,因?yàn)?poll 階段后面就是 check 階段

setImmediate(() => {
  console.log("timer1")

  Promise.resolve().then(function () {
    console.log("promise1")
  })
})

setTimeout(() => {
  console.log("timer2")

  Promise.resolve().then(function () {
    console.log("promise2")
  })
}, 0)

// Node輸出:
// timer1               timer2
// promise1    或者     promise2
// timer2               timer1
// promise2             promise1
fs.readFile("test.js", () => {
  setTimeout(() => console.log(1));
  setImmediate(() => console.log(2));
})

// 輸出 2 1

// 先進(jìn)入 I/O callbacks 階段,然后是 check 階段,最后才是 下一次事件循環(huán)的 timers 階段。因此,setImmediate 才會(huì)早于setTimeout 執(zhí)行。
示例
console.log(0)

new Promise(function(resolve) {
    console.log(1);
    resolve();
}).then(function() {
    console.log(2)
})

setTimeout(function() {
    console.log(3);
    new Promise(function(resolve) {
        console.log(4);
        resolve();
    }).then(function() {
        console.log(5)
    })
})

new Promise(function(resolve) {
    console.log(6);
    resolve();
}).then(function() {
    console.log(7)
})

setTimeout(function() {
    console.log(8);
    new Promise(function(resolve) {
        console.log(9);
        resolve();
    }).then(function() {
        console.log(10)
    })
})

console.log(11)
瀏覽器環(huán)境
第一輪事件循環(huán)

第一輪事件循環(huán)宏任務(wù)

開始執(zhí)行代碼,遇到 console.log 輸出 0

接著遇到 new Promise 其回調(diào)函數(shù)作為同步任務(wù)直接執(zhí)行

遇到 console.log 輸出 1

遇到 then 回調(diào)函數(shù)作為異步任務(wù)進(jìn)入“微任務(wù)隊(duì)列”

接著遇到 setTimeout 其回調(diào)函數(shù)作為異步任務(wù)進(jìn)入“宏任務(wù)隊(duì)列”

接著遇到 new Promise 其回調(diào)函數(shù)作為同步任務(wù)直接執(zhí)行

遇到 console.log 輸出 6

遇到 then 回調(diào)函數(shù)作為異步任務(wù)進(jìn)入“微任務(wù)隊(duì)列”

接著遇到 setTimeout 其回調(diào)函數(shù)作為異步任務(wù)進(jìn)入“宏任務(wù)隊(duì)列”

最后遇到 console.log 輸出 11

此時(shí)第一輪事件循環(huán)宏任務(wù)結(jié)束,依次輸出 0 1 6 11

第一輪事件循環(huán)微任務(wù)

執(zhí)行注冊(cè)在“微任務(wù)隊(duì)列”里的微任務(wù),遇到 then 執(zhí)行其回調(diào)輸出 2

遇到 then 執(zhí)行其回調(diào)輸出 7

此時(shí)第一輪事件循環(huán)微任務(wù)結(jié)束,依次輸出 2 7

第一輪事件循環(huán)結(jié)束,此時(shí)“微任務(wù)隊(duì)列”已被清空,“宏任務(wù)隊(duì)列”里有兩個(gè) setTimeout 的回調(diào)函數(shù),第一個(gè) setTimeout 被送入主線程執(zhí)行棧

第二輪事件循環(huán)

第二輪事件循環(huán)宏任務(wù)

開始執(zhí)行第一個(gè) setTimeout 回調(diào)函數(shù)

遇到 console.log 輸出 3

遇到 new Promise 其回調(diào)函數(shù)作為同步任務(wù)直接執(zhí)行

遇到 console.log 輸出 4

遇到 then 回調(diào)函數(shù)作為異步任務(wù)進(jìn)入“微任務(wù)隊(duì)列”

此時(shí)第二輪事件循環(huán)宏任務(wù)結(jié)束,依次輸出 3 4

第二輪事件循環(huán)微任務(wù)

執(zhí)行注冊(cè)在“微任務(wù)隊(duì)列”里的微任務(wù),遇到 then 執(zhí)行其回調(diào)輸出 5

此時(shí)第二輪事件循環(huán)微任務(wù)結(jié)束,輸出 5

第二輪事件循環(huán)結(jié)束,此時(shí)“微任務(wù)隊(duì)列”已被清空,“宏任務(wù)隊(duì)列”里剩下一個(gè) setTimeout 的回調(diào)函數(shù),其被送入主線程執(zhí)行棧

第三輪事件循環(huán)

第三輪事件循環(huán)宏任務(wù)

開始執(zhí)行第二個(gè) setTimeout 回調(diào)函數(shù)

遇到 console.log 輸出 8

遇到 new Promise 其回調(diào)函數(shù)作為同步任務(wù)直接執(zhí)行

遇到 console.log 輸出 9

遇到 then 回調(diào)函數(shù)作為異步任務(wù)進(jìn)入“微任務(wù)隊(duì)列”

此時(shí)第三輪事件循環(huán)宏任務(wù)結(jié)束,依次輸出 8 9

第三輪事件循環(huán)微任務(wù)

執(zhí)行注冊(cè)在“微任務(wù)隊(duì)列”里的微任務(wù),遇到 then 執(zhí)行其回調(diào)輸出 10

此時(shí)第三輪事件循環(huán)微任務(wù)結(jié)束,輸出 10

第三輪事件循環(huán)結(jié)束,此時(shí)“微任務(wù)隊(duì)列”已被清空,“宏任務(wù)隊(duì)列”已被清空

至此整段代碼執(zhí)行完畢,完整輸出結(jié)果為:0 1 6 11 2 7 3 4 5 8 9 10

Node.JS 環(huán)境
Node.JS 環(huán)境下任務(wù)隊(duì)列有層級(jí)之分,按層級(jí)執(zhí)行任務(wù)隊(duì)列
第一輪事件循環(huán)

第一輪事件循環(huán)宏任務(wù)

開始執(zhí)行代碼,遇到 console.log 輸出 0

接著遇到 new Promise 其回調(diào)函數(shù)作為同步任務(wù)直接執(zhí)行

遇到 console.log 輸出 1

遇到 then 回調(diào)函數(shù)作為異步任務(wù)進(jìn)入“微任務(wù)隊(duì)列”

接著遇到 setTimeout 其回調(diào)函數(shù)注冊(cè)到 timer 階段

接著遇到 new Promise 其回調(diào)函數(shù)作為同步任務(wù)直接執(zhí)行

遇到 console.log 輸出 6

遇到 then 回調(diào)函數(shù)作為異步任務(wù)進(jìn)入“微任務(wù)隊(duì)列”

接著遇到 setTimeout 其回調(diào)函數(shù)注冊(cè)到 timer 階段

最后遇到 console.log 輸出 11

此時(shí)第一輪事件循環(huán)宏任務(wù)結(jié)束,依次輸出 0 1 6 11

第一輪事件循環(huán)微任務(wù)

執(zhí)行注冊(cè)在“微任務(wù)隊(duì)列”里的微任務(wù),遇到 then 執(zhí)行其回調(diào)輸出 2

遇到 then 執(zhí)行其回調(diào)輸出 7

此時(shí)第一輪事件循環(huán)微任務(wù)結(jié)束,依次輸出 2 7

第一輪事件循環(huán)結(jié)束,此時(shí)“微任務(wù)隊(duì)列”已被清空,timer 隊(duì)列里有兩個(gè) setTimeout 的回調(diào)函數(shù)

第二輪事件循環(huán)

第二輪事件循環(huán) timer 階段

執(zhí)行第一個(gè) setTimeout 回調(diào)函數(shù)

遇到 console.log 輸出 3

遇到 new Promise 其回調(diào)函數(shù)作為同步任務(wù)直接執(zhí)行

遇到 console.log 輸出 4

遇到 then 回調(diào)函數(shù)作為異步任務(wù)進(jìn)入“微任務(wù)隊(duì)列”

執(zhí)行第二個(gè) setTimeout 回調(diào)函數(shù)

遇到 console.log 輸出 8

遇到 new Promise 其回調(diào)函數(shù)作為同步任務(wù)直接執(zhí)行

遇到 console.log 輸出 9

遇到 then 回調(diào)函數(shù)作為異步任務(wù)進(jìn)入“微任務(wù)隊(duì)列”

此時(shí)第二輪事件循 timer 階段結(jié)束,依次輸出 3 4 8 9

第二輪事件循環(huán) timer 階段微任務(wù)

執(zhí)行注冊(cè)在“微任務(wù)隊(duì)列”里的微任務(wù)

遇到 then 執(zhí)行其回調(diào)輸出 5

遇到 then 執(zhí)行其回調(diào)輸出 10

此時(shí)第二輪事件循環(huán) timer 階段微任務(wù)結(jié)束,輸出 5 10

第二輪事件循環(huán)結(jié)束,至此整段代碼執(zhí)行完畢,完整輸出結(jié)果為:0 1 6 11 2 7 3 4 8 9 5 10

參考文章
阮一峰 - JavaScript 運(yùn)行機(jī)制詳解:再談Event Loop

阮一峰 - Node 定時(shí)器詳解

Philip Roberts - Help,I’m stuck in an event loop

lynnelv - 深入理解js事件循環(huán)機(jī)制(Node.js篇)

這一次,徹底弄懂 JavaScript 執(zhí)行機(jī)制

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/101469.html

相關(guān)文章

  • 淺談JavaScript代碼預(yù)解析 + 示例詳解

    摘要:知識(shí)點(diǎn)聲明的變量在預(yù)解析的時(shí)候只執(zhí)行聲明,不會(huì)執(zhí)行定義,默認(rèn)值是。聲明的函數(shù)在預(yù)解析的時(shí)候會(huì)提前聲明并且會(huì)同時(shí)定義。 showImg(https://segmentfault.com/img/bVbnY76?w=2500&h=1250); 知識(shí)點(diǎn) var 聲明的變量在預(yù)解析的時(shí)候只執(zhí)行聲明,不會(huì)執(zhí)行定義,默認(rèn)值是 undefined。 function 聲明的函數(shù)在預(yù)解析的時(shí)候會(huì)...

    sunnyxd 評(píng)論0 收藏0
  • Java學(xué)習(xí)路線總結(jié),搬磚工逆襲Java架構(gòu)師(全網(wǎng)最強(qiáng))

    摘要:哪吒社區(qū)技能樹打卡打卡貼函數(shù)式接口簡介領(lǐng)域優(yōu)質(zhì)創(chuàng)作者哪吒公眾號(hào)作者架構(gòu)師奮斗者掃描主頁左側(cè)二維碼,加入群聊,一起學(xué)習(xí)一起進(jìn)步歡迎點(diǎn)贊收藏留言前情提要無意間聽到領(lǐng)導(dǎo)們的談話,現(xiàn)在公司的現(xiàn)狀是碼農(nóng)太多,但能獨(dú)立帶隊(duì)的人太少,簡而言之,不缺干 ? 哪吒社區(qū)Java技能樹打卡?【打卡貼 day2...

    Scorpion 評(píng)論0 收藏0
  • 2017文章總結(jié)

    摘要:歡迎來我的個(gè)人站點(diǎn)性能優(yōu)化其他優(yōu)化瀏覽器關(guān)鍵渲染路徑開啟性能優(yōu)化之旅高性能滾動(dòng)及頁面渲染優(yōu)化理論寫法對(duì)壓縮率的影響唯快不破應(yīng)用的個(gè)優(yōu)化步驟進(jìn)階鵝廠大神用直出實(shí)現(xiàn)網(wǎng)頁瞬開緩存網(wǎng)頁性能管理詳解寫給后端程序員的緩存原理介紹年底補(bǔ)課緩存機(jī)制優(yōu)化動(dòng) 歡迎來我的個(gè)人站點(diǎn) 性能優(yōu)化 其他 優(yōu)化瀏覽器關(guān)鍵渲染路徑 - 開啟性能優(yōu)化之旅 高性能滾動(dòng) scroll 及頁面渲染優(yōu)化 理論 | HTML寫法...

    dailybird 評(píng)論0 收藏0
  • 2017文章總結(jié)

    摘要:歡迎來我的個(gè)人站點(diǎn)性能優(yōu)化其他優(yōu)化瀏覽器關(guān)鍵渲染路徑開啟性能優(yōu)化之旅高性能滾動(dòng)及頁面渲染優(yōu)化理論寫法對(duì)壓縮率的影響唯快不破應(yīng)用的個(gè)優(yōu)化步驟進(jìn)階鵝廠大神用直出實(shí)現(xiàn)網(wǎng)頁瞬開緩存網(wǎng)頁性能管理詳解寫給后端程序員的緩存原理介紹年底補(bǔ)課緩存機(jī)制優(yōu)化動(dòng) 歡迎來我的個(gè)人站點(diǎn) 性能優(yōu)化 其他 優(yōu)化瀏覽器關(guān)鍵渲染路徑 - 開啟性能優(yōu)化之旅 高性能滾動(dòng) scroll 及頁面渲染優(yōu)化 理論 | HTML寫法...

    hellowoody 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

wanghui

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<