JS事件循环之宏任务和微任务
首先我们知道javascript是一个单线程的脚本语言,也就是说我们在执行代码的过程中不会出现同时进行两个进程(执行两段代码)。
JS 执行过程中会产生两种任务,分别是:同步任务和异步任务。
- 同步:一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息,那么这个进程将会一直等待下去,直到收到返回信息才继续执行下去。
比如声明语句、for、赋值等,读取后依据从上到下从左到右,立即执行。
- 异步:进程不需要一直等下去,而是继续执行下面的操作,不管其他进程的状态。当有消息返回时系统会通知进程进行处理,这样可以提高执行的效率。
比如ajax网络请求,setTimeout 定时函数等都属于异步任务。异步任务会通过任务队列(Event Queue)的机制(先进先出的机制)来进行协调。
任务队列(Event Queue)
任务队列中任务分为两种
-
宏任务,主要包括script(JS整体代码)、setTimeout、setInterval、setImmediate、I/O
-
微任务,主要包括Promise、process.nextTick(node.js)
任务(代码) | 宏/微任务 | 环境 |
---|---|---|
script | 宏任务 | 浏览器 |
事件 | 宏任务 | 浏览器 |
网络请求ajax | 宏任务 | 浏览器 |
setTimeout | 宏任务 | 浏览器/node |
setImmediate | 宏任务 | node |
Promise.then() | 微任务 | 浏览器/node |
process.nextTick | 微任务 | node |
任务队列的执行过程是
先执行一个宏任务,执行过程中如果产出新的宏/微任务,就将他们推入相应的任务队列,之后在执行一队微任务,之后再执行宏任务,如此循环。以上不断重复的过程就叫做 Event Loop(事件循环)。
console.log('script start')
new Promise((resolve, reject) => {
console.log('promise1')
resolve('promise2')
}).then((res) => {
console.log(res)
}).then((res)=> {
console.log('promise3')
})
setTimeout(() => {
console.log('setTimeout')
})
console.log('script end')
结果是:
- script start
- promise1
- script end
- promise2
- promise3
- setTimeout
1.宏任务:执行整体代码(相当于<script>
中的代码)
- 输出:script start
- 遇到 promise,输入promise1,直接resolve, 将then加入微任务,当前微任务队列promise 1。
- 遇到 setTimeout,加入宏任务队列,当前宏任务队列(setTimeout)
- 输出:script end
2.微任务:执行微任务队列(promise2)
- 输出:promise1,then之后产生一个微任务,加入微任务队列,当前微任务队列(promise2)
- 执行then,输出promise2
- 再执行then,输出promise3
4.微任务队列清空。
3.宏任务:执行setTimeout
1.输出:setTimeout