js的宏任务与微任务

在 JavaScript 中,宏任务(macrotask)和微任务(microtask)都是指待执行的任务,它们之间的区别在于它们的执行顺序和触发时机。

宏任务

  • setTimeout
  • setInterval
  • setImmediate (Node.js环境下)
  • I/O 操作
  • UI 渲染

宏任务通常包括整体代码中的任务、setTimeout、setInterval、requestAnimationFrame、UI 事件以及 I/O 操作等。当执行宏任务时,JavaScript 引擎会从宏任务队列中取出第一个宏任务执行,执行完毕后再执行下一个宏任务。

微任务

微任务是在当前宏任务执行完成后,立即执行的任务。它们也被称为 jobs,包括:

  • Promise.then()、Promise.catch()
  • Object.observe()
  • MutationObserver
  • process.nextTick (Node.js环境下)

当一个宏任务执行完毕后,事件循环会在它执行的上下文中查找微任务队列。如果找到微任务队列,它会按照队列中的顺序依次执行所有的微任务,直到队列为空。然后事件循环会再次从宏任务队列中取出队首任务执行。

因为微任务是在宏任务执行完成后立即执行的,所以它们的执行顺序优先于下一个宏任务。

当宏任务和微任务同时存在时,它们的执行顺序如下:

  1. 首先执行同步任务,执行完同步任务后会先执行所有微任务,直到微任务队列为空。
  2. 然后执行宏任务队列中的第一个宏任务,执行完宏任务后再执行所有微任务,依此类推。
  • 第一个小栗子
console.log('1');

setTimeout(function() {
  console.log('2');
  Promise.resolve().then(function() {
    console.log('3');
  });
}, 0);

Promise.resolve().then(function() {
  console.log('4');
});

console.log('5');

以上代码中,首先会执行整体代码中的任务,输出 15。然后,执行宏任务 setTimeout,将其回调函数添加到宏任务队列中,由于宏任务中有一个微任务 Promise.resolve().then(),因此会先执行微任务队列中的 4,再执行宏任务队列中的 2。最后,由于宏任务中又有一个微任务 Promise.resolve().then(),因此会执行微任务队列中的 3。因此,最终输出的结果为:

1
5
4
2
3

需要注意的是,不同的宏任务和微任务之间也是存在优先级关系的,例如 Promise 中的 then 回调会先于 MutationObserver 中的回调执行。因此,在实际开发中,需要仔细考虑任务的执行顺序,以避免出现不可预期的结果。

  • 第二个小栗子
console.log('start');

setTimeout(() => {
  console.log('timeout');
}, 0);

Promise.resolve().then(() => {
  console.log('promise');
});

console.log('end');

输出的结果是:

start
end
promise
timeout

可以看到,console.log(‘promise’) 是先于 console.log(‘timeout’) 执行的,因为 Promise.resolve().then() 是一个微任务,而 setTimeout 是一个宏任务。当 setTimeout 被添加到宏任务队列时,微任务队列已经有了任务,所以它们首先被执行。

  • 经典的栗子,面试题中常出
console.log('1');

setTimeout(() => {
  console.log('2');
  Promise.resolve().then(() => {
    console.log('3');
  });
}, 0);

Promise.resolve().then(() => {
  console.log('4');
});

console.log('5');

输出结果为:

1
5
4
2
3

解释如下:

  1. 执行同步任务,输出 1 和 5。
  2. 将 setTimeout 回调函数添加到宏任务队列中。
  3. 将 Promise 的 then 回调函数添加到微任务队列中。
  4. 执行宏任务队列中的第一个宏任务,即 setTimeout 回调函数,输出 2。
  5. 将 Promise 的 then 回调函数添加到微任务队列中。
  6. 执行微任务队列中的第一个微任务,即 Promise 的 then 回调函数,输出 4。
  7. 执行微任务队列中的第二个微任务,即 Promise 的 then

总之,理解宏任务和微任务对于理解 JavaScript 的事件循环非常重要。正确地使用它们可以优化代码的性能并避免一些常见的问题。

有什么错误或者需要改进的地方,希望大家不吝赐教。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值