深入了解微任务和宏任务

一、任务队列的概念

任务队列是JavaScript中实现异步编程的重要机制。在任务队列中,任务被分为两种类型:微任务和宏任务。在理解微任务和宏任务的区别之前,我们需要先了解任务队列的概念。


//伪代码
setTimeout(() => {
    console.log('task1');
}, 0);

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

console.log('task3');

在上述代码中,我们可以看到三个任务:task1、task2和task3。但是,它们并不是同步执行的,而是按照任务队列中的顺序依次被加入队列中。即task1首先被加入队列,在等待指定的时间后执行;task2作为微任务先被加入队列,在当前执行栈执行完成后执行;task3被加入队列,等待之前的任务执行完成后执行。

二、微任务和宏任务的区别

相较于宏任务,微任务是一类运行时机更加早的任务。

1. 执行时机不同

当后台任务队列的执行栈为空时,JavaScript引擎会从任务队列中取出一个任务并执行。每当一个任务执行结束,引擎就会检查是否需要执行微任务队列中的任务。只有在当前宏任务执行结束后才会执行微任务的队列。


//伪代码
console.log('task1');
setTimeout(() => {
  console.log('task2');
}, 2000);
Promise.resolve().then(() => {
  console.log('task3');
});
console.log('task4');

在上面的代码中,task1和task4是宏任务,其中task2是在2秒钟后被执行的宏任务,task3是在当前Promise执行完成后被执行的微任务。代码的执行顺序是:task1->task4->task3->task2。

2. 存储方式不同

宏任务的存储方式是一个个保存在任务队列中的,而微任务不同,它们是存在于宏任务中的,也就是说每个宏任务都有一个微任务队列。


//伪代码
setTimeout(() => {
  console.log('task1');
  Promise.resolve().then(() => {
    console.log('task2');
  });
}, 0);
console.log('task3');

在上面的代码中,我们可以看到setTimeout函数中除了一个宏任务task1,还有一个微任务task2。当task1被取出来执行时,task2也会被执行。代码的执行顺序是:task3->task1->task2。

3. 稳定性不同

由于微任务在当前宏任务执行结束前执行,所以它的执行过程中可能会影响到后续宏任务的执行顺序和结果。而宏任务则不存在这种稳定性问题。


//伪代码
setTimeout(() => {
  console.log('task1');
}, 0);
Promise.resolve().then(() => {
  console.log('task2');
  setTimeout(() => {
    console.log('task3');
  }, 0);
});
console.log('task4');

在上面的代码中,task1和task3是两个宏任务,task2是一个微任务。当JavaScript引擎执行到微任务task2时,它会加入setTimeout任务队列中,而此时我们并不能确定task1与task3到底哪一个先被执行,因此最后的执行结果也是不稳定的。

4. 举例说明


setTimeout(() => {
  console.log('task1');
}, 0);
Promise.resolve().then(() => {
  console.log('task2');
});
console.log('task3');

在上述代码中,task1是一个宏任务,task2是一个微任务,task3是另一个宏任务。会先执行task3,然后执行task2,最后是task1。

5. 微任务应用举例

微任务可以用来在事件循环的不同阶段间传递数据,并且能够帮助我们利用异步代码完成一些类似同步的任务。


function loadImage(url) {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.onload = () => {
      resolve(img);
    };
    img.onerror = (e) => {
      reject(e);
    };
    img.src = url;
  });
}

loadImage('https://picsum.photos/200/300').then((img) => {
  console.log('图片下载完成', img.width, img.height);
}).catch((e) => {
  console.log('图片下载失败', e);
});

console.log('图片下载开始');

在上述代码中,我们首先创建了一个Promise对象,将图片加载操作放在Promise的构造函数中,并将Promise对象返回。当该Promise执行成功后,会在当前宏任务执行结束前被划分为一个微任务,最后在当前宏任务执行完成后输出结果。

三、结尾与总结

通过以上的介绍,我们了解了微任务和宏任务的定义、执行时机、存储方式、稳定性等差异。在实际开发过程中,我们可以应用这些知识来更好地利用异步编程,提高程序的效率。

原创文章,作者:OJGRB,如若转载,请注明出处:https://www.506064.com/n/361882.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
OJGRBOJGRB
上一篇 2025-02-25 18:17
下一篇 2025-02-25 18:17

相关推荐

  • Java任务下发回滚系统的设计与实现

    本文将介绍一个Java任务下发回滚系统的设计与实现。该系统可以用于执行复杂的任务,包括可回滚的任务,及时恢复任务失败前的状态。系统使用Java语言进行开发,可以支持多种类型的任务。…

    编程 2025-04-29
  • Saturn 定时任务用法介绍

    本文将从以下几个方面对Saturn定时任务进行详细的阐述: 一、Saturn 定时任务简介 Saturn是一个分布式任务调度系统,支持在线添加、修改定时任务,支持多种任务类型,如J…

    编程 2025-04-29
  • 如何在dolphinscheduler中运行chunjun任务实例

    本文将从多个方面对dolphinscheduler运行chunjun任务实例进行详细的阐述,包括准备工作、chunjun任务配置、运行结果等方面。 一、准备工作 在运行chunju…

    编程 2025-04-28
  • dotask——高效易用的任务执行框架

    一、任务执行框架介绍 在一个复杂的系统中,通常存在大量的任务需要执行。这些任务包括但不限于:发送邮件、处理数据、调用服务、生成报表等。在传统的编程模式中,我们往往需要手动编写任务调…

    编程 2025-04-25
  • 深入解析Vue3 defineExpose

    Vue 3在开发过程中引入了新的API `defineExpose`。在以前的版本中,我们经常使用 `$attrs` 和` $listeners` 实现父组件与子组件之间的通信,但…

    编程 2025-04-25
  • 深入理解byte转int

    一、字节与比特 在讨论byte转int之前,我们需要了解字节和比特的概念。字节是计算机存储单位的一种,通常表示8个比特(bit),即1字节=8比特。比特是计算机中最小的数据单位,是…

    编程 2025-04-25
  • 深入理解Flutter StreamBuilder

    一、什么是Flutter StreamBuilder? Flutter StreamBuilder是Flutter框架中的一个内置小部件,它可以监测数据流(Stream)中数据的变…

    编程 2025-04-25
  • 深入探讨OpenCV版本

    OpenCV是一个用于计算机视觉应用程序的开源库。它是由英特尔公司创建的,现已由Willow Garage管理。OpenCV旨在提供一个易于使用的计算机视觉和机器学习基础架构,以实…

    编程 2025-04-25
  • 深入了解scala-maven-plugin

    一、简介 Scala-maven-plugin 是一个创造和管理 Scala 项目的maven插件,它可以自动生成基本项目结构、依赖配置、Scala文件等。使用它可以使我们专注于代…

    编程 2025-04-25
  • 深入了解LaTeX的脚注(latexfootnote)

    一、基本介绍 LaTeX作为一种排版软件,具有各种各样的功能,其中脚注(footnote)是一个十分重要的功能之一。在LaTeX中,脚注是用命令latexfootnote来实现的。…

    编程 2025-04-25

发表回复

登录后才能评论