JavaScript中的宏任务与微任务如何执行?

117 阅读2分钟

引言

我们知道JavaScript是单线程执行代码的,当js引擎从上往下执行代码时,会区分哪些代码是同步任务代码,哪些代码是异步任务。异步任务包括宏任务和微任务,js引擎会先执行完同步任务代码,再去执行异步任务代码。

宏任务

常见的宏任务:I/O,setTimeout,setInterval,setImmediate,Ajax等事件

微任务

常见的微任务:process.nextTick,MutationObserver,Promise.then/catch/finally

事件循环

当js引擎从上往下执行时,碰到宏任务,会将宏任务放进宏任务队列中等待;碰到微任务,会将微任务放进微任务队列中等待,直到将所有的同步任务执行结束,开始事件循环进行微任务和宏任务的执行。每个宏任务之后,引擎会立即执行微任务队列中的所有任务,然后再执行其他的宏任务,或者渲染。 例如:看下面示例:

setTimeout(()=> alert('张三'))

Promise.resolve().then(()=> alert('王五'))

alert('李四')

思考这里的执行顺序,在js引擎执行第一行代码,会把setTimeout的回调放进宏任务队列等待,执行第二行代码时,z执行.then方法后,会将.then的回调放入微任务队列,执行到第三行同步代码后,再开始去执行微任务队列里的所有任务,微任务执行完,去执行宏任务队列中的第一个任务。这个任务执行完再继续查看微任务队列是否有任务需要执行,以此循环。

所以执行顺序是:‘李四’,‘王五’,‘张三’

总结事件循环

  1. 从宏任务队列出队,并执行该宏任务
  2. 轮询微任务队列,队列非空时,执行所有的微任务
  3. 如果有变更,进行渲染
  4. 轮询宏任务队列,宏任务为空时,则等待新的任务;不为空时,转到步骤1

检验时刻

练习一下,看看理解到位了没,答案就在在下方。

console.log(1)

setTimeout(() => console.log(2), 3000)

Promise.resolve().then(() => console.log(3))

Promise.resolve().then(() => setTimeout(() => console.log(4), 2000))

Promise.resolve().then(() => console.log(5))

setTimeout(() => console.log(6), 1000)

console.log(7)

输出结果为:1 7 3 5 6 4 2

你做对了吗?