引言
在日常开发中我们经常会碰到需要setTimeout作为定时器,Promise作为解决回调hell的方法,有时面试的时候会碰到下面这样的面试题:
// 请将下面这段代码的执行结果写出来
console.log('test start');
setTimeout(function() {
console.log('timeout');
});
new Promise((resolve)=>{
console.log('promise 1');
resolve()
}).then(()=>{
console.log('promise 2')
})
console.log('test end');
这段代码的执行结果会是什么呢?
瞬间让大家懵圈了??????
宏任务与微任务
首先在浏览器测试一下上栗代码的执行情况:
test start
promise 1
test end
promise 2
timeout
涉及的概念
- 执行栈:所有的 JS 代码在运行时都是在执行上下文中进行的。
- eventTable
- eventQueue
代码分析
上面代码执行的流程图如下:
- 首先上面整个示例是个宏任务,当执行的时候,判断第一行代码是同步还是异步,第一行是同步任务,执行第一行代码输出
test start
- 然后到 setTimeout ,这是异步任务,异步的进入Event Table并注册函数, setTimeout 默认时间是0s;
- 接着执行 new Promise 这是个构造函数,构造函数的参数是同步的,先执行构造函数里面的函数,所以打印出了
promise 1
- new Promise 执行完后处理pendding状态,Promise 是微任务
- 继续执行,最后一句是 同步任务 ,输出
test end
- 第一次宏任务执行完毕,接着执行微任务——刚才那个 Promise 的状态由 Pending 切换到 Fulfilled,打印出
promise 2
- 微任务执行完后,待 event Table 的 setTimeout执行完后,
function() { console.log('timeout'); }
这个函数移入 event Queue ,主线程处理 Empty 状态,从 event Queue 里面拉取任务,将任务压入执行栈,继续执行本次宏任务,所以打印出timeout
宏任务与微任务的关系
常见宏任务与微任务
宏任务
宏任务,macrotask ,又叫 tasks 。一些异步任务的回调会依次进入 ** macro task queur** , 等待后续被调用,这些异步任务包括:
- setTimeout
- setInterval
- setImmediate(Node环境下独有)
- requestAnimationFrame(浏览器环境独有)
- I/O
- UI rendering(浏览器独有)
微任务
微任务,microtask,又叫 jobs。另外一些异步任务的回调会依次进入 micro task queue,等待后续被调用,这些异步任务包括:
- process.nextTick(Node环境独有)
- Promise.then()
- Object.observe
- MutationObserver
(备注: 以上列举的只是浏览器与Node环境)