宏任务
消息队列和事件循环中的任务都是宏任务。然后主线程采用一个 for 循环,不断地从这些任务队列中取出任务并执行任务。我们把这些消息队列中的任务称为宏任务。
宏任务可以满足我们大部分的日常需求,不过如果有对时间精度要求较高的需求,宏任务就难以胜任了,下面我们就来分析下为什么宏任务难以满足对时间精度要求较高的任务。
微任务
微任务就是一个需要异步执行的函数,执行时机是在主函数执行结束之后、当前宏任务结束之前。
微任务和宏任务是绑定的,每一个宏任务在创建时都会创建一个微任务队列。
我们先来看看微任务是怎么产生的?在现代浏览器里面,产生微任务有两种方式:
- 第一种方式是使用 MutationObserver 监控某个 DOM 节点,然后再通过 JavaScript 来修改这个节点,或者为这个节点添加、删除部分子节点,当 DOM 节点发生变化时,就会产生 DOM 变化记录的微任务。
- 第二种方式是使用 Promise,当调用
Promise.resolve()
或者Promise.reject()
的时候,也会产生微任务。
微任务执行的时机
在当前宏任务执行完成后,JavaScript不会立即执行下一个宏任务,而是会先检查当前宏任务对应的微任务队列,然后按顺序执行微任务队列中的微任务。WHATWG 把执行微任务的时间点称为检查点。
如果在执行微任务的过程中,产生了新的微任务,同样会将该微任务添加到微任务队列中,V8 引擎一直循环执行微任务队列中的任务,直到队列为空才算执行结束。也就是说在执行微任务过程中产生的新的微任务并不会推迟到下个宏任务中执行,而是在当前的宏任务中继续执行。