1. 宏任务和微任务
首先,我们要先了解下 JS。
js 是一种单线程语言,那么就产生了同步任务和异步任务。
js 同步任务和异步任务
ES6 规范中,microtask 称为 jobs,macrotask 称为 task
宏任务是由宿主发起的,而微任务由JavaScript自身发起。
2. 宏任务、微任务有哪些?
宏任务:
- script (可以理解为外层同步代码)
- setTimeout/setInterval
- UI rendering/UI事件
- postMessage,MessageChannel
- setImmediate
- I/O(Node.js)
微任务:
- Promise
- process.nextTick(Node.js)
- Object.observe(已废弃;Proxy 对象替代)
- MutaionObserver
3. 宏任务、微任务是怎么执行的?
执行顺序:
- 先执行同步代码
- 遇到异步宏任务则将异步宏任务放入宏任务队列中,遇到异步微任务则将异步微任务放入微任务队列中
- 当所有同步代码执行完毕后,再将异步微任务从队列中调入主线程执行
- 微任务执行完毕后再将异步宏任务从队列中调入主线程执行,一直循环直至所有任务执行完毕。
4. 经典案例
例三
console.log('1');
setTimeout(function() {
console.log('2');
process.nextTick(function() {
console.log('3');
})
new Promise(function(resolve) {
console.log('4');
resolve();
}).then(function() {
console.log('5')
})
})
process.nextTick(function() {
console.log('6');
})
new Promise(function(resolve) {
console.log('7');
resolve();
}).then(function() {
console.log('8')
})
setTimeout(function() {
console.log('9');
process.nextTick(function() {
console.log('10');
})
new Promise(function(resolve) {
console.log('11');
resolve();
}).then(function() {
console.log('12')
})
})
// 1 7 6 8 2 4 3 5 9 11 10 12
async function async1() {
console.log('async1 start') // 同步 2
await async2() // 同步
console.log('async1 end') // 异步 微任务 6
}
async function async2() {
console.log('async2') // 3
}
console.log('script start') // 1
setTimeout(() => {
console.log('setTimeout') // 8
}, 0);
async1()
new Promise(resolve => {
console.log('promise1') // 4
resolve()
})
.then(() => {
console.log('promise2') // 7
})
console.log('script end') // 5
运行结果:
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout
参考:
async函数的函数体可以被看作由0个或者多个await表达式分隔开来。从第一行代码知道第一个await表达式都在同步运行。这样的话,一个不含await表达式的async函数是同步运行的。
async function s(){
console.log(2);
}
async function foo(){
console.log(1); //同步
await s(); //同步
console.log(3); //从这里开始,await之后就是异步了
}
foo();
console.log(4)
//1 2 4 3