js Event loop 事件循环记录篇

53 阅读4分钟

js Event loop 事件循环记录篇

js event loop 知识点

  1. js 是单线程的
  2. 单线程任务又分为 同步任务异步任务
  3. 异步任务 又分为宏任务微任务

js 执行过程

<script> 标签开始,线程任务就开始按顺序进入了执行栈,

  • 当遇到同步任务在主线程中直接被执行
  • 当遇到异步任务时 会进入异步处理模块并注册相应的回调函数,注册完成后回调函数进入任务队列
  • 如果是宏任务会开启开启一个新的宏任务队列,如果遇到微任务进入微任务队列

每遇到一个宏任务会开启一个新的宏任务队列,而微任务队列只有一个 每次执行宏任务之前会检查是否存在微任务,如果存在则将微任务队列中的所有任务执行完后再执行宏任务

常见的宏任务

  • script(全局任务)
  • setTimeout
  • setInterval
  • setImmediate
  • I/O
  • UI render

常见的 微任务

  • Promise.then()/catch()/finally()
  • process.nextTick(node.js)
  • MutationObserver

js执行过程中,如果是同步任务,那么就会顺序执行下来,如果遇到宏任务执行函数就会开启一个新的宏任务队列,并将宏任务放入进去,如果遇到微任务执行函数,那么就会将这个函数放入到微队列中,待同步任务执行栈为空时,微任务依次进入栈中执行,每次执行宏任务之前会检查是否存在微任务,如果存在则将微任务队列中的所有任务执行完后再执行宏任务

DEMO1:

<script>
    console.log(1)
    
    setTimeout(() => {
        console.log(2)
    })
    
    new Promise((resolve, reject) => {
        console.log('3')
        resolve()
    }).then(() => {
        console.log(4)
    })
<script>
// 执行结果为:1 3 4 2

执行过程解析:

  1. script 标签就是一个宏任务,顺序执行script标签里面的代码
  2. 遇到 console.log(1) 为同步任务 则直接执行 输出 1
  3. 遇到setTimeout 函数为宏任务,新开启一个宏任务队列,将它放进去,先不执行,等同步任务和微任务跑完了再执行,
  4. 遇到promisepromise的函数是同步任务,所以直接输出 3 ,这时的结果是 1 3
  5. 之后promise调用then(),then() 是微任务,将它放入到微任务队列,等同步任务执行完之后就开始执行微任务
  6. 这时代码已经跑完了,没有同步任务了,这时就会去执行微队列中的微任务,微队列就只有一个then(),故输出4, 结果 1 3 4
  7. 微任务没有任务了,就去执行宏队列中的宏任务setTimeout,故结果为: 1 3 4 2

DEMO2:

new Promise((resolve, reject) => {
    console.log('2') // 1. 同步任务 2
    resolve()
}).then(() => {
    console.log('3') // 微任务
}).then(() => {
    console.log('4') // 微任务 之后的 二级微任务
})

new Promise((resolve, reject) => {
    resolve()
}).then(() => {
    console.log('12') // 微任务
}).then(() => {
    console.log('13') // 微任务 之后的 二级微任务
}).then(() => {
    console.log('14') // 二级微任务 之后的 三级微任务
})

Promise.resolve().then(() => {
    console.log('5') // 微任务
})

let _promise = () => new Promise((resolve, reject) => {
    console.log('6') // 同步任务
    resolve()
})

setTimeout(() => {
    console.log('7') // 宏任务
    Promise.resolve().then(() => {
        console.log('8')
    })
}, 100)

setTimeout(() => { 
    console.log('9') // 宏任务
}, 0)

_promise().then(() => {
    console.log('10') // 微任务
})

console.log('11'); // 同步任务

执行结果:2 6 11 3 12 5 10 4 13 14 9 7 8

执行过程:

1、先顺序执行同步任务,得到的结果为:2 6 11

2、在执行微任务: 首先执行一级微任务,之后执行二级微任务

第一个then(),第二个then() 我们称之为第二级微任务,以此类推...

2.1、执行完一级微任务之后的结果为:`2 6 11, 3 12 5 10`

2.2、接着执行二级微任务:`2 6 11, 3 12 5 10,4 13` 

2.3接着执行三级微任务:`2 6 11, 3 12 5 10,4 13,14` 

3、自此微任务执行结束,接着执行新的宏任务:

setTimeout 延迟最短的先执行,故这边先执行 setTimeout 延迟为 0console.log('9')

3.1 执行完第一个宏任务之后的结果为:`2 6 11, 3 12 5 10,4 13,14,9`

3.2、接着继续执行延迟为 `100``setTimeout`的第二个宏任务:
        执行之后的结果为:`2 6 11, 3 12 5 10,4 13,14,9, 7 8`

自此所有的函数执行完毕,得到的结果为:

  1. 同步代码执行之后得到:2 6 11
  2. 一级微任务执行之后得到:3 12 5 10
  3. 二级微任务执行之后得到:4 13,
  4. 三级微任务执行之后得到:14
  5. 第一个宏任务执行之后得到:9
  6. 第二个宏任务执行之后得到:7 8

总结得到的结果为:2 6 11 3 12 5 10 4 13 14 9 7 8.