经常有根据代码写出js执行结果的问题,往往考察的是对js在浏览器中执行机制的理解。如果了解不够深入,那么结果往往会谬以千里。
-
任务队列
宏任务(macrotask)和微任务(microtask)
macrotask: script(整体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering。
microtask:process.nextTick, Promise.then, Object.observe, MutationObserver。
宏任务队列有多个,微任务队列只有一个。
-
事件循环
对于事件循环,用自己的话概括为:
先执行宏任务。将整体代码(Script)作为第一个宏任务进入执行栈。
若遇到同步代码(包含promise而非promise.then)直接执行;
若遇到异步任务时,微任务则将其放入微任务队列,宏任务则将其放入宏任务队列;
当执行栈为空时,则先将微任务从微任务队列中取出,放入执行栈中执行,
当微任务队列执行完成之后,再执行宏任务队列。
重复以上过程。
借用一张图片说明该过程:
结合实例:
async function asyncA(){
console.log('1')
await asyncB()
console.log('2')
}
async function asyncB(){
console.log('3')
}
console.log('4')
setTimeout(function(){
console.log('5')
},0)
asyncA();
new Promise(function(resolve){
console.log('6')
resolve();
}).then(function(){
console.log('7')
})
console.log('8')
结果:4,1,3,6,8,2,7,5
其中,console.log('4')为主线程代码,直接先执行。
promise中resolve()同步先执行,而Promise.then()会放入微任务队列等待执行;
async1();前面无await, console.log('1')会同步先执行。
await 是promise的语法糖,await async2();console.log('2') 等价于 Promise.resolve(async2()).then(()=>{console.log('2') }),故console.log('3')也会按顺序同步先执行,而console.log('2')放入微任务队列等待执行。
setTimeout()放入宏任务队列等待执行。