欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JS面試之對(duì)事件循環(huán)的理解

 更新時(shí)間:2022年09月26日 09:19:40   作者:febobo  
這篇文章主要為大家介紹了JS面試之對(duì)事件循環(huán)的理解分析詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

一、是什么

JavaScript 在設(shè)計(jì)之初便是單線程,即指程序運(yùn)行時(shí),只有一個(gè)線程存在,同一時(shí)間只能做一件事

為什么要這么設(shè)計(jì),跟JavaScript的應(yīng)用場(chǎng)景有關(guān)

JavaScript 初期作為一門(mén)瀏覽器腳本語(yǔ)言,通常用于操作 DOM ,如果是多線程,一個(gè)線程進(jìn)行了刪除 DOM ,另一個(gè)添加 DOM,此時(shí)瀏覽器該如何處理?

為了解決單線程運(yùn)行阻塞問(wèn)題,JavaScript用到了計(jì)算機(jī)系統(tǒng)的一種運(yùn)行機(jī)制,這種機(jī)制就叫做事件循環(huán)(Event Loop)

事件循環(huán)(Event Loop)

JavaScript中,所有的任務(wù)都可以分為

  • 同步任務(wù):立即執(zhí)行的任務(wù),同步任務(wù)一般會(huì)直接進(jìn)入到主線程中執(zhí)行
  • 異步任務(wù):異步執(zhí)行的任務(wù),比如ajax網(wǎng)絡(luò)請(qǐng)求,setTimeout 定時(shí)函數(shù)等

同步任務(wù)與異步任務(wù)的運(yùn)行流程圖如下:

從上面我們可以看到,同步任務(wù)進(jìn)入主線程,即主執(zhí)行棧,異步任務(wù)進(jìn)入任務(wù)隊(duì)列,主線程內(nèi)的任務(wù)執(zhí)行完畢為空,會(huì)去任務(wù)隊(duì)列讀取對(duì)應(yīng)的任務(wù),推入主線程執(zhí)行。上述過(guò)程的不斷重復(fù)就是事件循環(huán)

二、宏任務(wù)與微任務(wù)

如果將任務(wù)劃分為同步任務(wù)和異步任務(wù)并不是那么的準(zhǔn)確,舉個(gè)例子:

console.log(1)
setTimeout(()=>{
    console.log(2)
}, 0)
new Promise((resolve, reject)=>{
    console.log('new Promise')
    resolve()
}).then(()=>{
    console.log('then')
})
console.log(3)

如果按照上面流程圖來(lái)分析代碼,我們會(huì)得到下面的執(zhí)行步驟:

  • console.log(1) ,同步任務(wù),主線程中執(zhí)行
  • setTimeout() ,異步任務(wù),放到 Event Table,0 毫秒后console.log(2) 回調(diào)推入 Event Queue 中
  • new Promise ,同步任務(wù),主線程直接執(zhí)行
  • .then ,異步任務(wù),放到 Event Table
  • console.log(3),同步任務(wù),主線程執(zhí)行

所以按照分析,它的結(jié)果應(yīng)該是 1 => 'new Promise' => 3 => 2 => 'then'

但是實(shí)際結(jié)果是:1=>'new Promise'=> 3 => 'then' => 2

出現(xiàn)分歧的原因在于異步任務(wù)執(zhí)行順序,事件隊(duì)列其實(shí)是一個(gè)“先進(jìn)先出”的數(shù)據(jù)結(jié)構(gòu),排在前面的事件會(huì)優(yōu)先被主線程讀取

例子中 setTimeout回調(diào)事件是先進(jìn)入隊(duì)列中的,按理說(shuō)應(yīng)該先于 .then 中的執(zhí)行,但是結(jié)果卻偏偏相反

原因在于異步任務(wù)還可以細(xì)分為微任務(wù)與宏任務(wù)

微任務(wù)

一個(gè)需要異步執(zhí)行的函數(shù),執(zhí)行時(shí)機(jī)是在主函數(shù)執(zhí)行結(jié)束之后、當(dāng)前宏任務(wù)結(jié)束之前

常見(jiàn)的微任務(wù)有:

  • Promise.then
  • MutaionObserver
  • Object.observe(已廢棄;Proxy 對(duì)象替代)
  • process.nextTick(Node.js)

宏任務(wù)

宏任務(wù)的時(shí)間粒度比較大,執(zhí)行的時(shí)間間隔是不能精確控制的,對(duì)一些高實(shí)時(shí)性的需求就不太符合

常見(jiàn)的宏任務(wù)有:

  • script (可以理解為外層同步代碼)
  • setTimeout/setInterval
  • UI rendering/UI事件
  • postMessage、MessageChannel
  • setImmediate、I/O(Node.js)

這時(shí)候,事件循環(huán),宏任務(wù),微任務(wù)的關(guān)系如圖所示

按照這個(gè)流程,它的執(zhí)行機(jī)制是:

  • 執(zhí)行一個(gè)宏任務(wù),如果遇到微任務(wù)就將它放到微任務(wù)的事件隊(duì)列中
  • 當(dāng)前宏任務(wù)執(zhí)行完成后,會(huì)查看微任務(wù)的事件隊(duì)列,然后將里面的所有微任務(wù)依次執(zhí)行完

回到上面的題目

console.log(1)
setTimeout(()=>{
    console.log(2)
}, 0)
new Promise((resolve, reject)=>{
    console.log('new Promise')
    resolve()
}).then(()=>{
    console.log('then')
})
console.log(3)

流程如下

// 遇到 console.log(1) ,直接打印 1
// 遇到定時(shí)器,屬于新的宏任務(wù),留著后面執(zhí)行
// 遇到 new Promise,這個(gè)是直接執(zhí)行的,打印 'new Promise'
// .then 屬于微任務(wù),放入微任務(wù)隊(duì)列,后面再執(zhí)行
// 遇到 console.log(3) 直接打印 3
// 好了本輪宏任務(wù)執(zhí)行完畢,現(xiàn)在去微任務(wù)列表查看是否有微任務(wù),發(fā)現(xiàn) .then 的回調(diào),執(zhí)行它,打印 'then'
// 當(dāng)一次宏任務(wù)執(zhí)行完,再去執(zhí)行新的宏任務(wù),這里就剩一個(gè)定時(shí)器的宏任務(wù)了,執(zhí)行它,打印 2

三、async與await

async 是異步的意思,await 則可以理解為等待

放到一起可以理解async就是用來(lái)聲明一個(gè)異步方法,而 await 是用來(lái)等待異步方法執(zhí)行

async

async函數(shù)返回一個(gè)promise對(duì)象,下面兩種方法是等效的

function f() {
    return Promise.resolve('TEST');
}
// asyncF is equivalent to f!
async function asyncF() {
    return 'TEST';
}

await

正常情況下,await命令后面是一個(gè) Promise 對(duì)象,返回該對(duì)象的結(jié)果。如果不是 Promise 對(duì)象,就直接返回對(duì)應(yīng)的值

async function f(){
    // 等同于
    // return 123
    return await 123
}
f().then(v => console.log(v)) // 123

不管await后面跟著的是什么,await都會(huì)阻塞后面的代碼

async function fn1 (){
    console.log(1)
    await fn2()
    console.log(2) // 阻塞
}
async function fn2 (){
    console.log('fn2')
}
fn1()
console.log(3)

上面的例子中,await 會(huì)阻塞下面的代碼(即加入微任務(wù)隊(duì)列),先執(zhí)行 async 外面的同步代碼,同步代碼執(zhí)行完,再回到 async 函數(shù)中,再執(zhí)行之前阻塞的代碼

所以上述輸出結(jié)果為:1,fn2,3,2

四、流程分析

通過(guò)對(duì)上面的了解,我們對(duì)JavaScript對(duì)各種場(chǎng)景的執(zhí)行順序有了大致的了解

這里直接上代碼:

async function async1() {
    console.log('async1 start')
    await async2()
    console.log('async1 end')
}
async function async2() {
    console.log('async2')
}
console.log('script start')
setTimeout(function () {
    console.log('settimeout')
})
async1()
new Promise(function (resolve) {
    console.log('promise1')
    resolve()
}).then(function () {
    console.log('promise2')
})
console.log('script end')

分析過(guò)程:

  • 執(zhí)行整段代碼,遇到 console.log('script start') 直接打印結(jié)果,輸出 script start
  • 遇到定時(shí)器了,它是宏任務(wù),先放著不執(zhí)行
  • 遇到 async1(),執(zhí)行 async1 函數(shù),先打印 async1 start,下面遇到await怎么辦?先執(zhí)行 async2,打印 async2,然后阻塞下面代碼(即加入微任務(wù)列表),跳出去執(zhí)行同步代碼
  • 跳到 new Promise 這里,直接執(zhí)行,打印 promise1,下面遇到 .then(),它是微任務(wù),放到微任務(wù)列表等待執(zhí)行
  • 最后一行直接打印 script end,現(xiàn)在同步代碼執(zhí)行完了,開(kāi)始執(zhí)行微任務(wù),即 await 下面的代碼,打印 async1 end
  • 繼續(xù)執(zhí)行下一個(gè)微任務(wù),即執(zhí)行 then 的回調(diào),打印 promise2
  • 上一個(gè)宏任務(wù)所有事都做完了,開(kāi)始下一個(gè)宏任務(wù),就是定時(shí)器,打印 settimeout

所以最后的結(jié)果是:script start、async1 start、async2、promise1、script end、async1 end、promise2、settimeout

以上就是JS面試之對(duì)事件循環(huán)的理解的詳細(xì)內(nèi)容,更多關(guān)于JS面試事件循環(huán)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 利用騰訊的ip地址庫(kù)做ip物理地址定位

    利用騰訊的ip地址庫(kù)做ip物理地址定位

    騰訊的這個(gè)還是相對(duì)比較準(zhǔn)確的。因?yàn)轵v訊每個(gè)QQ用戶(hù)發(fā)現(xiàn)自己匹配的地理位置信息不準(zhǔn)確都可以提交更正的
    2010-07-07
  • js生成隨機(jī)數(shù)(指定范圍)的實(shí)例代碼

    js生成隨機(jī)數(shù)(指定范圍)的實(shí)例代碼

    下面小編就為大家?guī)?lái)一篇js生成隨機(jī)數(shù)(指定范圍)的實(shí)例代碼。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-07-07
  • 微信小程序地圖標(biāo)記多個(gè)位置的方法詳解

    微信小程序地圖標(biāo)記多個(gè)位置的方法詳解

    地圖是我們平時(shí)經(jīng)常用到的組件,而且地圖是顯示在最高層的原生組件,下面這篇文章主要給大家介紹了關(guān)于微信小程序地圖標(biāo)記多個(gè)位置的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-04-04
  • js判斷文本框剩余可輸入字?jǐn)?shù)的方法

    js判斷文本框剩余可輸入字?jǐn)?shù)的方法

    這篇文章主要介紹了js判斷文本框剩余可輸入字?jǐn)?shù)的方法,可實(shí)現(xiàn)直觀顯示文本框可輸入字?jǐn)?shù)的功能,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2015-02-02
  • addeventlistener監(jiān)聽(tīng)scroll跟touch(實(shí)例講解)

    addeventlistener監(jiān)聽(tīng)scroll跟touch(實(shí)例講解)

    下面小編就為大家?guī)?lái)一篇addeventlistener監(jiān)聽(tīng)scroll跟touch(實(shí)例講解)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-08-08
  • 使用Vue3實(shí)現(xiàn)一個(gè)Upload組件的示例代碼

    使用Vue3實(shí)現(xiàn)一個(gè)Upload組件的示例代碼

    這篇文章主要介紹了使用Vue3實(shí)現(xiàn)一個(gè)Upload組件的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-05-05
  • js+h5 canvas實(shí)現(xiàn)圖片驗(yàn)證碼

    js+h5 canvas實(shí)現(xiàn)圖片驗(yàn)證碼

    這篇文章主要為大家詳細(xì)介紹了js+h5 canvas實(shí)現(xiàn)圖片驗(yàn)證碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-10-10
  • JavaScript閉包原理與用法實(shí)例分析

    JavaScript閉包原理與用法實(shí)例分析

    這篇文章主要介紹了JavaScript閉包原理與用法,結(jié)合實(shí)例形式分析了javascript閉包的概念、功能、常見(jiàn)問(wèn)題及相關(guān)操作技巧,需要的朋友可以參考下
    2018-08-08
  • 生產(chǎn)制造追溯系統(tǒng)之再說(shuō)條碼打印

    生產(chǎn)制造追溯系統(tǒng)之再說(shuō)條碼打印

    這篇文章主要介紹了生產(chǎn)制造追溯系統(tǒng)之再說(shuō)條碼打印,本文圖文并茂給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-06-06
  • 用javascript連接access數(shù)據(jù)庫(kù)的方法

    用javascript連接access數(shù)據(jù)庫(kù)的方法

    用javascript連接access數(shù)據(jù)庫(kù)的方法...
    2006-11-11

最新評(píng)論