浅谈Event loop
JS的运行机制
JS是单线程的,但鉴于浏览器中有很多事件都是异步的,所以浏览器会开启多个线程去执行任务。
执行栈与任务队列
执行栈是JS脚本在运行过程中线程执行代码的顺序。一般最先开始压入执行栈的是main函数,根据先进后出的原则,只有等函数完全执行结束才会从栈中弹出,而任务队列是因为在栈执行的过程中会出现异步函数,这时候就需要把该函数丢给WebAPIs,等WebAPIs执行完后会放入任务队列中,当栈为空时会把回调函数压入栈中执行。要注意的是,任务队列中只会存在异步函数。

什么是宏任务与微任务
宏任务(macrotask)是一个event loop有一个或者多个task队列,常见的task的任务源有:
- setTimeout
- setInterval
- setImmediate
- I/O
- UI rendering
微任务(microtask) 队列和task 队列有些相似,都是先进先出的队列,由指定的任务源去提供任务,不同的是一个 event loop里只有一个microtask 队列,同一个执行环境下为人物要先于红任务执行,只有微任务队列执行为空时才会执行宏任务队列。
一个例子:
Promise.resolve().then(function promise1 () {
console.log('promise1');
})
setTimeout(function setTimeout1 (){
console.log('setTimeout1')
Promise.resolve().then(function promise2 () {
console.log('promise2');
})
}, 0)
setTimeout(function setTimeout2 (){
console.log('setTimeout2')
}, 0)
运行过程:
script里的代码被列为一个task,放入task队列。
循环1:
- 【task队列:script ;microtask队列:】
- 从task队列中取出script任务,推入栈中执行。
- promise1列为microtask,setTimeout1列为task,setTimeout2列为task。
- 【task队列:setTimeout1 setTimeout2;microtask队列:promise1】
- script任务执行完毕,执行microtask checkpoint,取出microtask队列的promise1执行。
循环2:
*【task队列:setTimeout1 setTimeout2;microtask队列:】 4. 从task队列中取出setTimeout1,推入栈中执行,将promise2列为microtask。
- 【task队列:setTimeout2;microtask队列:promise2】
- 执行microtask checkpoint,取出microtask队列的promise2执行。
循环3:
- 【task队列:setTimeout2;microtask队列:】
- 从task队列中取出setTimeout2,推入栈中执行。 7.setTimeout2任务执行完毕,执行microtask checkpoint。
- 【task队列:;microtask队列:】
拓展demo:
console.log('script start') async function async1() { await async2() console.log('async1 end') } async function async2() { console.log('async2 end') } async1() setTimeout(function() { console.log('setTimeout') }, 0) new Promise(resolve => { console.log('Promise') resolve() }) .then(function() { console.log('promise1') }) .then(function() { console.log('promise2') }) console.log('script end')

浙公网安备 33010602011771号