幾道常見面試題來看
JavaScript
執行機制
根據 JavaScript
的運行環境,鎖定它爲單線程,任務須要排隊執行,若是網站資源比較大,這樣會致使瀏覽器加載會很慢,但實際上並無,你們確定馬上想到了同步和異步。面試
所謂的同步和異步也是在排隊,只是排隊的地方不一樣。promise
同步任務進入主線程排隊,異步任務進入事件隊列中排隊
同步任務和異步任務進入到不一樣的隊列中,也就是上面講的在不一樣地方排隊。瀏覽器
同步任務進入主線程,異步任務進入事件隊列,主線程任務執行完畢,事件隊列中有等待執行的任務進入主線程執行,直到事件隊列中任務所有執行完畢。異步
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
並非馬上執行,只是表明相比於其餘定時器更早的進入主線程中執行。code
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。
除了常常說的同步任務和異步任務以外,更可分爲宏任務,微任務
主要宏任務:整段腳本script
setTimeout
setTimeout
...
主要微任務:promise.then
...
執行流程:
const p = new Promise(resolve => { console.log('a') resolve() console.log('b') }) p.then(() => { console.log('c') }) console.log('d')
結果:a b d c
promise
建立當即執行,打印 a
b
,promise.then
進入微任務隊列,console.log('d')
打印 d
,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')
結果:a b d c setTimeout
setTimeout
進入宏任務隊列,promise
建立當即執行,打印 a
b
,promise.then
進入微任務隊列,console.log('d')
打印 d
,c
,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
c
,遇到 setTimeout
將其推入宏任務隊列中setTimeout
then中的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
a
promise
當即執行,打印 b
promise.then
推入微任務隊列setTimeout
推入宏任務隊列c
,遇到 setTimeout
推入宏任務隊列排隊等待執行h j
,promise.then
推入微任務隊列i
,繼續執行宏任務,打印 d
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_then') 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
並非馬上執行,只是表明相比於其餘定時器更早的被執行