# 事件循环(EventLoop)

有没有想过,为什么有时候SetTimeout定时不准确?

更新时间:2019-04-24

下面这两道题,会输出什么?

console.log(1)

setTimeout(() => {
    console.log(2)
}, 0)

Promise.resolve().then(() => {
    console.log(3)
    Promise.resolve().then(() => {
        console.log(4)
    }).then(() => {
        console.log(5)
    })
}).then(() => {
    console.log(6)
})

Promise.resolve().then(() => {
    console.log(7)
}).then(() => {
    console.log(8)
})

console.log(9)

// 1 9 3 7 4 6 8 5 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
async function async1() {
  console.log('a')
  await async2()
  console.log('b')
}
async function async2() {
  console.log('c')
}
console.log('d')
setTimeout(function () {
  console.log('e')
}, 0)
async1()
new Promise(function (resolve) {
  console.log('f')
  resolve()
}).then(function () {
  console.log('g')
})
console.log('h')

// d a c f h b g e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

总结:

  • await紧跟的Promise相当于new Promise,会立即执行
  • await下面的代码,相当于promise.then(代码),视作微任务
  • Promise内代码执行完Promise.resolve(),都会开始执行promise.then,视作微任务
  • setTimeout属于宏任务(由 事件触发线程 维护)
  • 要注意Promise的状态变更时机

# 1、执行栈(call stack)

当JS调用一个函数时,会产生这个函数对应的执行上下文(context),并把这个函数作为一个 栈帧 压入执行栈里。

执行上下文存放了这个函数的作用域、上层作用域的指向、函数的参数、函数中声明的变量等。

alt

# 2、Web APIs

JS运行时是单线程,但是浏览器不是。浏览器提供了一些api供开发者使用。

  • 例如setTimeout、ajax(XMLHttpRequest)、DOM等。

# 3、宏任务(Macro Task)、微任务(Micro Task)

宏任务:当前调用栈中、宏任务队列中的任务。

  • 例如:主代码块(所有同步代码)、Ajax请求完毕后的回调函数、setTimeout、setInterval、setImmediate、I/O、
  • 宏任务由事件触发线程维护。

微任务:当前微任务队列中的任务。会在 当前调用栈的所有任务执行完、且在下一个宏任务开始前需要执行的任务。

  • 例如:Promise.then、catch、finally
  • 微任务队列由JS引擎线程维护。

# EventLoop

alt

解释如下:

  • 1、JS引擎 首先会把 主函数 放入 宏任务队列(此时宏任务队列只有一个任务,那就是主代码块
  • 2、从宏任务队列中取出一个宏任务
  • 3、从上往下执行。
    • 如果遇到同步代码,直接执行、输出
    • 如果遇到setTimeout之类的宏任务,将其进宏任务队列
    • 如果遇到Promise.then之类的微任务,将其送进微任务队列
  • 4、当前执行栈中宏任务全部执行完毕,执行栈为空。JS引擎 会去检查微任务队列是否有任务在排队
  • 5、执行微任务队列中的微任务(先进先出)
  • 6、微任务队列中微任务全部执行完毕,本轮事件循环结束
  • 7、回到第2步,检查宏任务队列中是否有未执行的宏任务,继续下一轮循环

注意:Ajax请求完毕后触发的回调函数会进入宏任务队列

参考链接:JavaScript的Event Loop机制

更新时间: 5/6/2020, 9:26:25 PM