宏队列和微队列

发布于:2024-07-05 ⋅ 阅读:(19) ⋅ 点赞:(0)

js的宏队列和微队列

  • 说明

    • JS中用来存储待执行回调函数的队列包含2个不同特定的列队
    • 宏列队: 用来保存待执行的宏任务(回调), 比如: 定时器回调/DOM事件回调/ajax回调
    • 微列队: 用来保存待执行的微任务(回调), 比如: promise的回调/MutationObserver的回调
    • JS执行时会区别这2个队列
      • JS引擎首先必须先执行所有的初始化同步任务代码
      • 每次准备取出第一个宏任务执行前, 都要将所有的微任务一个一个取出来执行
  • 微任务(Microtasks)

微任务是为了优化异步代码的执行而设计的,通常用于需要尽快执行的场景,比如 Promise 的回调。
微任务的例子包括:Promise 回调、MutationObserver、process.nextTick(在 Node.js 中)。
微任务队列是在当前任务执行完毕后立即执行的,即在主线程空闲时,微任务队列中的任务会被优先执行。
微任务可以添加新的微任务到队列中,并且会在当前任务执行完毕后立即执行这些新添加的微任务。

  • 宏任务(Macrotasks)

宏任务通常与浏览器或 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

  • 案例2

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 解决或拒绝后执行的。

  • 案例3

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
  • 案例4

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

网站公告

今日签到

点亮在社区的每一天
去签到