js的宏队列和微队列
-
说明
- JS中用来存储待执行回调函数的队列包含2个不同特定的列队
- 宏列队: 用来保存待执行的宏任务(回调), 比如: 定时器回调/DOM事件回调/ajax回调
- 微列队: 用来保存待执行的微任务(回调), 比如: promise的回调/MutationObserver的回调
- JS执行时会区别这2个队列
- JS引擎首先必须先执行所有的初始化同步任务代码
- 每次准备取出第一个宏任务执行前, 都要将所有的微任务一个一个取出来执行
-
微任务(Microtasks)
微任务是为了优化异步代码的执行而设计的,通常用于需要尽快执行的场景,比如 Promise 的回调。
微任务的例子包括:Promise 回调、MutationObserver、process.nextTick(在 Node.js 中)。
微任务队列是在当前任务执行完毕后立即执行的,即在主线程空闲时,微任务队列中的任务会被优先执行。
微任务可以添加新的微任务到队列中,并且会在当前任务执行完毕后立即执行这些新添加的微任务。
宏任务通常与浏览器或 Node.js 的 I/O 操作相关,比如定时器、事件监听、网络请求等。
宏任务的例子包括:setTimeout、setInterval、setImmediate(在 Node.js 中)、I/O 操作、UI 渲染等。
宏任务会按照顺序添加到任务队列中,并且会在微任务队列清空后执行。
宏任务可以添加新的宏任务或微任务到队列中。
执行同步代码,直到执行栈为空。
执行所有微任务队列中的任务,如果在执行微任务的过程中又添加了新的微任务,也会在这个周期内执行。
如果有需要,执行 UI 渲染。
执行宏任务队列中的一个任务。
重复步骤 2-4。
console.log('同步代码开始');
// 微任务
Promise.resolve().then(() => {
console.log('微任务 1');
});
// 宏任务
setTimeout(() => {
console.log('宏任务 1');
}, 0);
// 微任务
Promise.resolve().then(() => {
console.log('微任务 2');
});
console.log('同步代码结束');
// 执行顺序:
// 同步代码开始
// 同步代码结束
// 微任务 1
// 微任务 2
// 宏任务 1
console.log('同步代码开始');
// 微任务
Promise.resolve().then(() => {
console.log('微任务 1');
});
// 宏任务
setTimeout(() => {
console.log(1)
}, 0)
new Promise((resolve) => {
console.log(2);//同步
resolve()
}).then(() => {
console.log(3)
}).then(() => {
console.log(4)
})
console.log(5)
// 执行顺序:
// 同步任务2
// 同步任务5
// 微任务 3
// 微任务 4
// 宏任务 1
注意:
在 JavaScript 中,Promise 构造函数中的回调是同步执行的,而 Promise 的 then 方法中的回调是异步执行的(作为微任务)。这是因为 Promise 构造函数中的回调是为了初始化 Promise 的状态,而 then 方法中的回调是为了在 Promise 解决或拒绝后执行的。
const first = () => (new Promise((resolve, reject) => {
console.log(3);//同步任务
let p = new Promise((resolve, reject) => {
console.log(7);//同步任务
setTimeout(() => {
console.log(5);//宏任务
resolve(6)
}, 0)
resolve(1)
})
resolve(2)
p.then((arg) => {
console.log(arg);//微任务 返回1
})
}))
first().then((arg) => {
console.log(arg);//微任务 返回2
})
console.log(4);//同步任务
//3,7,4,1,2,5
setTimeout(() => {
console.log("0") //宏任务
}, 0)
new Promise((resolve, reject) => {
console.log("1");//同步任务
resolve()
}).then(() => {
console.log("2");
//第一个 Promise 构造函数中的 resolve 被调用,使得 then 方法中的回调被添加到微任务队列中。
//当主线程的同步代码执行完毕后,开始执行微任务队列中的任务,打印出 2
new Promise((resolve, reject) => {
console.log("3")//发现有同步任务,立即执行
resolve()
}).then(() => {
console.log("4")//微任务
}).then(() => {
console.log("5")//微任务
})
}).then(() => {
console.log("6");//微任务
})
new Promise((resolve, reject) => {
console.log("7")//同步任务
resolve()
}).then(() => {
console.log("8")//微任务
});
//1, 7, 2, 3,8, 4, 6, 5, 0