微任务和宏任务有什么区别

简介: 微任务和宏任务是JavaScript异步编程中的两个概念。宏任务包括整体代码块、setTimeout等,微任务有Promise、MutationObserver等。主要区别在于执行时机:每次事件循环中,宏任务只执行一个,而微任务会在当前宏任务结束后、下一个宏任务开始前全部执行完毕。
  1. 定义与概念

    • 宏任务(Macro - Task):宏任务是浏览器或JavaScript运行环境中的一个较大的任务单元,通常包括一些比较耗时或者不那么紧急的操作。例如,script(整体脚本)、setTimeoutsetIntervalI/O操作(如Ajax请求)、postMessageMessageChannel等都属于宏任务。它们构成了任务队列(Task Queue)中的主要部分,这些任务的执行顺序遵循一定的规则,在事件循环(Event Loop)中按顺序逐个被处理。
    • 微任务(Micro - Task):微任务是一种相对较小、更紧急的任务,它们通常是在当前宏任务执行结束后,下一个宏任务开始之前需要立即执行的任务。常见的微任务包括Promise.then()MutationObserverprocess.nextTick(在Node.js环境下)等。微任务队列(Micro - Task Queue)用于存储这些微任务,并且在宏任务执行间隙优先清空微任务队列。
  2. 执行顺序与时机

    • 宏任务执行顺序:在JavaScript的单线程执行模型中,首先执行全局script代码,这是第一个宏任务。当这个宏任务执行过程中遇到异步的宏任务(如setTimeout),会将其回调函数添加到宏任务队列的末尾。只有当当前宏任务以及微任务队列都为空时,才会从宏任务队列中取出下一个宏任务执行。例如:
      console.log('Script start');
      setTimeout(() => {
             
      console.log('Timeout 1');
      }, 0);
      setTimeout(() => {
             
      console.log('Timeout 2');
      }, 0);
      console.log('Script end');
      
    • 在这个例子中,首先执行script这个宏任务,打印Script start,然后遇到两个setTimeout,它们的回调函数被添加到宏任务队列。接着打印Script end,此时当前宏任务结束。由于微任务队列没有任务,所以开始从宏任务队列中取出任务执行,先执行第一个setTimeout的回调函数打印Timeout 1,再执行第二个setTimeout的回调函数打印Timeout 2
    • 微任务执行顺序:在每个宏任务执行结束后,JavaScript引擎会立即检查微任务队列。如果微任务队列中有任务,会按照先进先出(FIFO)的顺序依次执行这些微任务,直到微任务队列清空。例如:
      console.log('Script start');
      const promise1 = Promise.resolve();
      promise1.then(() => {
             
      console.log('Promise 1');
      });
      const promise2 = Promise.resolve();
      promise2.then(() => {
             
      console.log('Promise 2');
      });
      console.log('Script end');
      
    • 在这里,首先执行script宏任务,打印Script start。然后promise1promise2.then回调函数作为微任务被添加到微任务队列。接着打印Script end,此时当前宏任务结束,开始执行微任务队列中的任务,按照添加顺序先打印Promise 1,再打印Promise 2
  3. 对应用性能和行为的影响

    • 宏任务对性能的影响:由于宏任务相对比较耗时,过多的宏任务或者长时间运行的宏任务可能会导致页面的延迟和卡顿。例如,一个复杂的setInterval定时器在每次执行回调函数时进行大量的计算或者DOM操作,可能会占用较长的时间,使得后续的任务(包括渲染任务)被延迟。特别是当宏任务中包含I/O操作(如网络请求)时,等待响应的时间可能会不确定,这也会影响整个应用的响应性能。
    • 微任务对性能的影响:微任务通常用于处理一些对及时性要求较高的操作,它们的执行相对比较快速。但是,如果微任务队列中的任务过多或者某个微任务执行时间过长,也可能会阻塞下一个宏任务的执行,从而影响到整个事件循环的节奏。不过,由于微任务本身是在宏任务间隙执行的,所以在合理使用的情况下,它们可以帮助我们在不阻塞主要任务流程的情况下及时处理一些小的、重要的操作,如更新UI状态等。
    • 应用行为方面的差异:在应用行为上,宏任务更适合用于处理一些可以延迟执行或者周期性执行的任务,如定时更新数据、延迟加载资源等。而微任务则常用于在异步操作完成后立即进行一些后续处理,并且这些处理通常与当前的执行上下文紧密相关,如在Promise成功或失败后立即进行相应的状态更新或者错误处理。例如,在一个基于Promise的异步数据加载应用中,使用微任务来更新UI显示加载成功的数据,能够确保在数据加载完成后及时、同步地更新界面,提供更好的用户体验。
相关文章
|
前端开发 JavaScript 测试技术
函数柯里化的应用场景
函数柯里化在编程中广泛应用,如参数复用、提前返回部分计算结果、提高代码可读性和模块化程度。常见于函数式编程语言,也可在JavaScript等语言中实现,简化复杂操作。
|
存储 Prometheus 监控
评估系统的可用性时间
评估系统可用性时间是指对系统在预定时间内正常运行的能力进行测量和分析,以确保其稳定性和可靠性满足用户需求。这通常涉及对系统故障率、恢复时间和维护周期的综合考量。
|
存储 程序员 编译器
C 语言中的数据类型转换:连接不同数据世界的桥梁
C语言中的数据类型转换是程序设计中不可或缺的一部分,它如同连接不同数据世界的桥梁,使得不同类型的变量之间能够互相传递和转换,确保了程序的灵活性与兼容性。通过强制类型转换或自动类型转换,C语言允许开发者在保证数据完整性的前提下,实现复杂的数据处理逻辑。
|
Java API 调度
如何避免 Java 中的 TimeoutException 异常
在Java中,`TimeoutException`通常发生在执行操作超过预设时间时。要避免此异常,可以优化代码逻辑,减少不必要的等待;合理设置超时时间,确保其足够完成正常操作;使用异步处理或线程池管理任务,提高程序响应性。
597 13
|
消息中间件 人工智能 运维
1月更文特别场——寻找用云高手,分享云&AI实践
我们寻找你,用云高手,欢迎分享你的真知灼见!
3297 69
1月更文特别场——寻找用云高手,分享云&AI实践
|
11月前
|
数据采集 监控 数据管理
智能数据建设与治理 Dataphin深度评测
作为一名金融行业数据分析师,我在构建反洗钱监测系统时深度使用了阿里云DataPhin。以下从合规能力、核心功能实践及待优化体验三方面进行评测:1) 合规能力上,细粒度权限控制满足监管要求,数据质量校验有效降低人工成本;2) 核心功能中,开发协作加速模型迭代,数据服务API支撑实时决策;3) 待优化方面,元数据管理和监控预警系统需增强。同时提出开发金融合规模板、融合区块链技术等建议,助力提升金融场景适用性。
289 18
|
11月前
|
存储 弹性计算 运维
深度评测——大模型时代的智能BI—Quick BI
作为一名运维工程师,我近期深度体验了Quick BI,从部署、监控、成本优化、安全合规等方面分享评测报告。其弹性伸缩功能可节省人工干预成本,全链路日志追踪大幅缩短故障排查时间,冷数据归档降低存储成本。但目前存在伸缩策略颗粒度粗、日志分析工具不足等问题。总体而言,Quick BI适合中大型企业构建高效稳定的BI平台,尤其在运维成本控制和故障响应效率上有显著优势。
478 17
|
存储 数据管理 C语言
C 语言中的文件操作:数据持久化的关键桥梁
C语言中的文件操作是实现数据持久化的重要手段,通过 fopen、fclose、fread、fwrite 等函数,可以实现对文件的创建、读写和关闭,构建程序与外部数据存储之间的桥梁。
|
Java
在Java中如何将基本数据类型转换为String
在Java中,可使用多种方法将基本数据类型(如int、char等)转换为String:1. 使用String.valueOf()方法;2. 利用+运算符与空字符串连接;3. 对于数字类型,也可使用Integer.toString()等特定类型的方法。这些方法简单高效,适用于不同场景。
881 7