用幾道面試題來看JavaScript執行機制
前面的話
根據javascript的執行環境,鎖定它為單執行緒,任務需要排隊執行,如果網站資源比較大,這樣會導致瀏覽器載入會很慢,但實際上並沒有,大家肯定立刻想到了同步和非同步。
所謂的同步和非同步也是在排隊,只是排隊的地方不同。
同步和非同步
同步任務進入主執行緒排隊,非同步任務進入事件佇列中排隊
同步任務和非同步任務進入到不同的佇列中,也就是上面講的在不同地方排隊。
同步任務進入主執行緒,非同步任務進入事件佇列,主執行緒任務執行完畢,事件佇列中有等待執行的任務進入主執行緒執行,直到事件佇列中任務全部執行完畢。
開胃菜
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延遲一段時間執行,顧名思義非同步任務進入事件佇列中,等待主執行緒任務執行完畢,再進入主執行緒執行。
定時器的延遲時間為0並不是立刻執行,只是代表相比於其他定時器更早的進入主執行緒中執行。
加一盤
for(var i = 0; i < 10; i++) { setTimeout(function() { console.log(i) },1000) }
結果:十個10
每次for迴圈遇到setTimeout將其放入事件佇列中等待執行,直到全部迴圈結束,i作為全域性變數當迴圈結束後i = 10,再來執行setTimeout時i的值已經為10, 結果為十個10。
將var改為let,變數作用域不同,let作用在當前迴圈中,所以進入事件佇列的定時器每次的i不同,最後列印結果會是 0 1 2...9。
巨集任務 微任務
除了經常說的同步任務和非同步任務之外,更可分為巨集任務,微任務
主要巨集任務:整http://www.cppcns.com段指令碼scriptsetTimeoutsetTimeout...
主要微任務:promise.then...
執行流程:
1.整段指令碼script作為巨集任務開始執行
2.遇到微任務將其推入微任務佇列,巨集任務推入巨集任務佇列
3.巨集任務執行完畢,檢查有沒有可執行的微任務
4.發現有可執行的微任務,將所有微任務執行完畢
5.開始新的巨集任務,反覆如此直到所有任務執行完畢
來一盤Promise
const p = new Promise(resolve => { console.log('a') resolve() console.log('b') }) p.then(() => { console.log('c') }) console.log('d')
結果:a b d c
1.整段script進入巨集任務佇列開始執行
2.promise建立立即執行,列印ab
3.遇到promise.then進入微任務佇列
4.遇到console.log('d')列印d
5.整段程式碼作為巨集任務執行完畢,有可執行的微任務,開始執行微任務,列印c。
setTimeout(function(){ console.log('setTimeo程式設計客棧ut') },0) const p = new Promise(resolve => { console.log('a') resolve() http://www.cppcns.com console.log('b') }) p.then(() => { console.log('c') }) console.log('d')
結果:a b d c setTimeout
1.setTimeout進入巨集任務佇列
2.promise建立立即執行,列印ab
3.遇到promise.then進入微任務佇列
4.遇到console.log('d')列印d
5.有可執行的微任務,列印c
6.微任務執行完畢,開始執行新的巨集任務,setTimeout開始執行,列印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')
結果:a b d c setTimeout then中的setTimeout
1.同上
2.執行微任務列印c,遇到setTimeout將其推入巨集任務佇列中
3.定時器延遲時間相同,開始按照順序執行巨集任務,分別列印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)
結果:a b c h j i d e f g
1.列印a
2.promise立即執行,列印b
3.promise.then推入微任務佇列
4.setTimeout推入巨集任務佇列
5.整段程式碼執行完畢,開始執行微任務,列印c,遇到setTimeout推入巨集任務佇列排隊等待執行
6.沒有可執行的微任務開始執行巨集任務,定時器按照延遲時間排隊執行
7.列印h j,promise.then推入微任務佇列有
8.可執行的微任務,列印i,繼續執行巨集任務,列印d
9.執行延遲為100的巨集任務,列印e f,執行微任務列印g,所有任務執行完畢
簡單測試
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_th程式設計客棧en')
return Promise.resolve('a方法的返回值')
})
}
function b() {
console.log('b_function')
return Promise.resolve('返回值')
}
結果:start a_function b_function end res 返回值 b_then a_then
根據上面例子的流程講解來思考這個,加深理解
總結
- javaScript單執行緒,任務需要排隊執行
- 同步任務進入主執行緒排隊,非同步任務進入事件佇列排隊等待被推入主執行緒執
- 行定時器的延遲時間為0並不是立刻執行,只是代表相比於其他定時器更早的被執行
- 以巨集任務和微任務進一步理解js執行機制
- 整段程式碼作為巨集任務開始執行,執行過程中巨集任務和微任務進入相應的佇列中
- 整段程式碼執行結束,看微任務佇列中是否有任務等待執行,如果有則執行所有的微任務,直到微任務佇列中的任務執行完畢,如果沒有則繼續
- 執行新的巨集任務執行新的巨集任務,凡是在執行巨集任務過程中遇到微任務都將其推入微任務佇列中執行
- 反覆如此直到所有任務全部執行完畢
以上就是用幾道面試題來看JavaScript執行機制的詳細內容,更多關於JavaScript執行機制的資料請關注我們其它相關文章!