什么是宏任务和微任务
- 宏任务包括:setTimeout setInterval Ajax DOM事件
- 微任务:Promise async/await
- 微任务比宏任务的执行时间要早
同步和异步
JS是单线程执行的语言,在同一个时间只能做一件事情。这就导致后面的任务需要等到前面的任务完成才能执行,如果前面的任务很耗时就会造成后面的任务一直等待。为了解决这个问题JS中出现了同步任务和异步任务。
同步任务:
在主线程上排队执行的任务只有前一个任务执行完毕,才能执行后一个任务,形成一个执行栈。
异步任务:
不进入主线程,而是进入任务队列,当主线程中的任务执行完毕,就从任务队列中取出任务放进主线程中来进行执行。由于主线程不断重复的获得任务、执行任务、再获取再执行,所以者种机制被叫做事件循环(Event Loop)
我们都知道 Js 是单线程的,但是一些高耗时操作带来了进程阻塞的问题。为了解决这个问题,Js 有两种任务的执行模式:同步模式(Synchronous)和异步模式(Asynchronous)
在异步模式下,创建异步任务主要分为宏任务与微任务两种。ES6 规范中,宏任务(Macrotask) 称为 Task, 微任务(Microtask) 称为 Jobs。
注意
宏任务是由宿主(浏览器、Node)发起的,而微任务由 JS 自身发起。
宏任务(Macrotask)大概如下:setTimeout setInterval MessageChannel I/O
setImmediate(Node环境) script(整体代码块)
微任务(Microtask)大概如下:MutationObserver(浏览器环境) promise.[ then/catch/finally ]
事件队列 process.nextTick(Node环境)
一、主线程上宏任务、微任务执行顺序
在这里插入代码片
console.log('---start---');//第一轮主线程
setTimeout(() => {
console.log('setTimeout'); // 将回调代码放入个宏任务队列,第二轮宏任务执行
}, 0);
new Promise((resolve, reject) => {
console.log('---Promise第一轮微任务同步执行---');//第一轮微任务同步执行
resolve()
}).then(()=>{
console.log('Promise.then实例成功回调执行'); // 将回调代码放入微任务队列,第一轮宏任务执行完后立即执行
});
console.log('---end---');//第一轮主线程结束
—start—
—Promise第一轮微任务同步执行
——end—
Promise.then实例成功回调执行
undefined
setTimeout
执行顺序:主线程 >> 主线程上创建的微任务 >> 主线程上创建的宏任务
二、宏任务中包含微任务
// 宏任务队列 1
setTimeout(() => {
// 宏任务队列 2.1
console.log('timer_1');
setTimeout(() => {
// 宏任务队列 3
console.log('timer_3')
}, 0)
new Promise(resolve => {
resolve()
console.log('new promise')
}).then(() => {
// 微任务队列 1
console.log('promise then')
})
}, 0)
setTimeout(() => {
// 宏任务队列 2.2
console.log('timer_2')
}, 0)
console.log('========== Sync queue ==========')
========== Sync queue ==========
1 timer_1
2 new promise
3 promise then
4 timer_2
5 timer_3
执行顺序:主线程 >> 主线程上的宏任务队列1 >> 宏任务队列1中创建的微任务
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0)
async1();
new Promise(function(resolve) {
console.log('promise1');
resolve();
}).then(function() {
console.log('promise2');
});
console.log('script end');