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

