用幾道面試題來看JavaScript執(zhí)行機(jī)制
前面的話
根據(jù)JavaScript的運(yùn)行環(huán)境,鎖定它為單線程,任務(wù)需要排隊(duì)執(zhí)行,如果網(wǎng)站資源比較大,這樣會(huì)導(dǎo)致瀏覽器加載會(huì)很慢,但實(shí)際上并沒有,大家肯定立刻想到了同步和異步。
所謂的同步和異步也是在排隊(duì),只是排隊(duì)的地方不同。
同步和異步
同步任務(wù)進(jìn)入主線程排隊(duì),異步任務(wù)進(jìn)入事件隊(duì)列中排隊(duì)
同步任務(wù)和異步任務(wù)進(jìn)入到不同的隊(duì)列中,也就是上面講的在不同地方排隊(duì)。
同步任務(wù)進(jìn)入主線程,異步任務(wù)進(jìn)入事件隊(duì)列,主線程任務(wù)執(zhí)行完畢,事件隊(duì)列中有等待執(zhí)行的任務(wù)進(jìn)入主線程執(zhí)行,直到事件隊(duì)列中任務(wù)全部執(zhí)行完畢。
開胃菜
console.log('a') setTimeout(function(){ console.log('b') }, 200) setTimeout(function(){ console.log('c') }, 0) console.log('d')
a d c b
從上到下,該進(jìn)入主線程的進(jìn)入主線程,該進(jìn)入事件隊(duì)列的進(jìn)入事件隊(duì)列。
那么主線程中存在console.log('a')和console.log('d'),定時(shí)器setTimeout延遲一段時(shí)間執(zhí)行,顧名思義異步任務(wù)進(jìn)入事件隊(duì)列中,等待主線程任務(wù)執(zhí)行完畢,再進(jìn)入主線程執(zhí)行。
定時(shí)器的延遲時(shí)間為0并不是立刻執(zhí)行,只是代表相比于其他定時(shí)器更早的進(jìn)入主線程中執(zhí)行。
加一盤
for(var i = 0; i < 10; i++) { setTimeout(function() { console.log(i) }, 1000) }
結(jié)果:十個(gè)10
每次for循環(huán)遇到setTimeout將其放入事件隊(duì)列中等待執(zhí)行,直到全部循環(huán)結(jié)束,i作為全局變量當(dāng)循環(huán)結(jié)束后i = 10,再來執(zhí)行setTimeout時(shí)i的值已經(jīng)為10, 結(jié)果為十個(gè)10。
將var改為let,變量作用域不同,let作用在當(dāng)前循環(huán)中,所以進(jìn)入事件隊(duì)列的定時(shí)器每次的i不同,最后打印結(jié)果會(huì)是 0 1 2...9。
宏任務(wù) 微任務(wù)
除了經(jīng)常說的同步任務(wù)和異步任務(wù)之外,更可分為宏任務(wù),微任務(wù)
主要宏任務(wù):整段腳本scriptsetTimeoutsetTimeout...
主要微任務(wù):promise.then...
執(zhí)行流程:
1.整段腳本script作為宏任務(wù)開始執(zhí)行
2.遇到微任務(wù)將其推入微任務(wù)隊(duì)列,宏任務(wù)推入宏任務(wù)隊(duì)列
3.宏任務(wù)執(zhí)行完畢,檢查有沒有可執(zhí)行的微任務(wù)
4.發(fā)現(xiàn)有可執(zhí)行的微任務(wù),將所有微任務(wù)執(zhí)行完畢
5.開始新的宏任務(wù),反復(fù)如此直到所有任務(wù)執(zhí)行完畢
來一盤Promise
const p = new Promise(resolve => { console.log('a') resolve() console.log('b') }) p.then(() => { console.log('c') }) console.log('d')
結(jié)果:a b d c
1.整段script進(jìn)入宏任務(wù)隊(duì)列開始執(zhí)行
2.promise創(chuàng)建立即執(zhí)行,打印ab
3.遇到promise.then進(jìn)入微任務(wù)隊(duì)列
4.遇到console.log('d')打印d
5.整段代碼作為宏任務(wù)執(zhí)行完畢,有可執(zhí)行的微任務(wù),開始執(zhí)行微任務(wù),打印c。
setTimeout(function(){ console.log('setTimeout') }, 0) const p = new Promise(resolve => { console.log('a') resolve() console.log('b') }) p.then(() => { console.log('c') }) console.log('d')
結(jié)果:a b d c setTimeout
1.setTimeout進(jìn)入宏任務(wù)隊(duì)列
2.promise創(chuàng)建立即執(zhí)行,打印ab
3.遇到promise.then進(jìn)入微任務(wù)隊(duì)列
4.遇到console.log('d')打印d
5.有可執(zhí)行的微任務(wù),打印c
6.微任務(wù)執(zhí)行完畢,開始執(zhí)行新的宏任務(wù),setTimeout開始執(zhí)行,打印setTimeout
setTimeout(function(){ console.log('setTimeout') }, 0) const p = new Promise(resolve => { console.log('a') resolve() console.log('b') }) p.then(() => { console.log('c') setTimeout(function(){ console.log('then中的setTimeout') }, 0) }) console.log('d')
結(jié)果:a b d c setTimeout then中的setTimeout
1.同上
2.執(zhí)行微任務(wù)打印c,遇到setTimeout將其推入宏任務(wù)隊(duì)列中
3.定時(shí)器延遲時(shí)間相同,開始按照順序執(zhí)行宏任務(wù),分別打印setTimeoutthen中的setTimeout
再加點(diǎn)定時(shí)器
console.log('a'); new Promise(resolve => { console.log('b') resolve() }).then(() => { console.log('c') setTimeout(() => { console.log('d') }, 0) }) setTimeout(() => { console.log('e') new Promise(resolve => { console.log('f') resolve() }).then(() => { console.log('g') }) }, 100) setTimeout(() => { console.log('h') new Promise(resolve => { resolve() }).then(() => { console.log('i') }) console.log('j') }, 0)
結(jié)果:a b c h j i d e f g
1.打印a
2.promise立即執(zhí)行,打印b
3.promise.then推入微任務(wù)隊(duì)列
4.setTimeout推入宏任務(wù)隊(duì)列
5.整段代碼執(zhí)行完畢,開始執(zhí)行微任務(wù),打印c,遇到setTimeout推入宏任務(wù)隊(duì)列排隊(duì)等待執(zhí)行
6.沒有可執(zhí)行的微任務(wù)開始執(zhí)行宏任務(wù),定時(shí)器按照延遲時(shí)間排隊(duì)執(zhí)行
7.打印h j,promise.then推入微任務(wù)隊(duì)列有
8.可執(zhí)行的微任務(wù),打印i,繼續(xù)執(zhí)行宏任務(wù),打印d
9.執(zhí)行延遲為100的宏任務(wù),打印e f,執(zhí)行微任務(wù)打印g,所有任務(wù)執(zhí)行完畢
簡(jiǎn)單測(cè)試
console.log('start') a().then(() => { console.log('a_then') }) console.log('end') function a() { console.log('a_function') return b().then((res) => { console.log('res', res) console.log('b_then') return Promise.resolve('a方法的返回值') }) } function b() { console.log('b_function') return Promise.resolve('返回值') }
結(jié)果:start a_function b_function end res 返回值 b_then a_then
根據(jù)上面例子的流程講解來思考這個(gè),加深理解
總結(jié)
- JavaScript單線程,任務(wù)需要排隊(duì)執(zhí)行
- 同步任務(wù)進(jìn)入主線程排隊(duì),異步任務(wù)進(jìn)入事件隊(duì)列排隊(duì)等待被推入主線程執(zhí)
- 行定時(shí)器的延遲時(shí)間為0并不是立刻執(zhí)行,只是代表相比于其他定時(shí)器更早的被執(zhí)行
- 以宏任務(wù)和微任務(wù)進(jìn)一步理解js執(zhí)行機(jī)制
- 整段代碼作為宏任務(wù)開始執(zhí)行,執(zhí)行過程中宏任務(wù)和微任務(wù)進(jìn)入相應(yīng)的隊(duì)列中
- 整段代碼執(zhí)行結(jié)束,看微任務(wù)隊(duì)列中是否有任務(wù)等待執(zhí)行,如果有則執(zhí)行所有的微任務(wù),直到微任務(wù)隊(duì)列中的任務(wù)執(zhí)行完畢,如果沒有則繼續(xù)
- 執(zhí)行新的宏任務(wù)執(zhí)行新的宏任務(wù),凡是在執(zhí)行宏任務(wù)過程中遇到微任務(wù)都將其推入微任務(wù)隊(duì)列中執(zhí)行
- 反復(fù)如此直到所有任務(wù)全部執(zhí)行完畢
以上就是用幾道面試題來看JavaScript執(zhí)行機(jī)制的詳細(xì)內(nèi)容,更多關(guān)于JavaScript執(zhí)行機(jī)制的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
關(guān)于layui導(dǎo)航欄不展示下拉列表的解決方法
今天小編就為大家分享一篇關(guān)于layui導(dǎo)航欄不展示下拉列表的解決方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-09-09JavaScript實(shí)現(xiàn)網(wǎng)站訪問次數(shù)統(tǒng)計(jì)代碼
每個(gè)網(wǎng)站管理者,都必須知道每天有多少人訪問了本站,需要一個(gè)網(wǎng)站訪問次數(shù)功能來滿足需求,本篇文章主要介紹了JavsScript實(shí)現(xiàn)網(wǎng)站訪問次數(shù)統(tǒng)計(jì)代碼,需要的朋友可以參考下2015-08-08JS格式化字符串的兩種方法(反引號(hào)與String.prototype)
本文一共介紹了兩種實(shí)現(xiàn)方式,使用反引號(hào)或自定義方法實(shí)現(xiàn),需要的朋友可以參考下2023-06-06JS對(duì)象轉(zhuǎn)換為Jquery對(duì)象示例
JS對(duì)象轉(zhuǎn)換為Jquery對(duì)象的方便在于可以使用jquery的一些方法,下面有個(gè)示例,大家可以參考下2014-01-01javaScript的函數(shù)對(duì)象的聲明詳解
這篇文章主要介紹了javaScript的函數(shù)對(duì)象的聲明詳解,需要的朋友可以參考下2015-02-02微信小程序?qū)崿F(xiàn)評(píng)價(jià)功能
這篇文章主要為大家詳細(xì)介紹了微信小程序?qū)崿F(xiàn)評(píng)價(jià)功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08