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

简介: 微任务和宏任务是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显示加载成功的数据,能够确保在数据加载完成后及时、同步地更新界面,提供更好的用户体验。
相关文章
|
12月前
|
前端开发 JavaScript 测试技术
函数柯里化的应用场景
函数柯里化在编程中广泛应用,如参数复用、提前返回部分计算结果、提高代码可读性和模块化程度。常见于函数式编程语言,也可在JavaScript等语言中实现,简化复杂操作。
|
JavaScript 索引
Vue 3.x 版本中双向数据绑定的底层实现有哪些变化
从Vue 2.x的`Object.defineProperty`到Vue 3.x的`Proxy`,实现了更高效的数据劫持与响应式处理。`Proxy`不仅能够代理整个对象,动态响应属性的增删,还优化了嵌套对象的处理和依赖追踪,减少了不必要的视图更新,提升了性能。同时,Vue 3.x对数组的响应式处理也更加灵活,简化了开发流程。
|
12月前
|
前端开发
在Webpack配置文件中,如何配置loader以处理其他类型的文件,如CSS或图片
在Webpack配置文件中,通过设置`module.rules`来配置loader处理不同类型的文件。例如,使用`css-loader`和`style-loader`处理CSS文件,使用`file-loader`或`url-loader`处理图片等资源文件。配置示例:在`rules`数组中添加对应规则,指定`test`匹配文件类型,`use`指定使用的loader。
|
12月前
|
存储 数据安全/隐私保护
如何选择使用字节流还是字符流
在处理文件或网络数据时,选择字节流(如InputStream/OutputStream)适合处理二进制数据,而字符流(如Reader/Writer)则适用于文本数据,能自动处理字符编码问题,确保文本正确读写。选择依据主要看数据类型及是否需要编码转换。
236 3
|
12月前
|
JavaScript 前端开发 Java
实现函数的柯里化
本文介绍了在JavaScript、Python和Java三种编程语言中实现函数柯里化的具体方法。JavaScript通过自定义`curry`函数实现,Python利用`functools.partial`简化过程,而Java则通过定义辅助函数达成目的。每种语言的实现细节虽有差异,但均能有效支持函数的分步参数传递与调用。
|
12月前
|
前端开发 JavaScript
宏任务和微任务在浏览器渲染过程中的执行顺序
宏任务和微任务是浏览器事件循环中的两种任务类型。宏任务包括整体代码块、setTimeout等,微任务有Promise.then、MutationObserver等。每个宏任务执行完毕后,会先执行完所有微任务,再进行下一轮渲染或执行下一个宏任务。
|
人工智能 Rust Java
10月更文挑战赛火热启动,坚持热爱坚持创作!
开发者社区10月更文挑战,寻找热爱技术内容创作的你,欢迎来创作!
2736 44
|
11月前
|
数据采集 DataWorks 搜索推荐
阿里云DataWorks深度评测:实战视角下的全方位解析
在数字化转型的大潮中,高效的数据处理与分析成为企业竞争的关键。本文深入评测阿里云DataWorks,从用户画像分析最佳实践、产品体验、与竞品对比及Data Studio公测体验等多角度,全面解析其功能优势与优化空间,为企业提供宝贵参考。
504 13
|
12月前
|
存储 安全 数据挖掘
《C 语言字符串处理:从基础操作到高级应用》
《C 语言字符串处理:从基础操作到高级应用》全面介绍了C语言中字符串的处理方法,从基本概念、常见操作到复杂应用,适合初学者及有经验的开发者参考学习。本书通过丰富实例讲解,帮助读者掌握字符串处理技巧。
|
12月前
|
JSON 前端开发 JavaScript
Proxy + Fetch 实现类似于 axios 的基础 API
本项目通过 Proxy 和 Fetch 技术实现了一个类似 axios 的基础 API,支持请求拦截、响应处理等功能,简化了前端网络请求的开发流程,提升了代码的可维护性和扩展性。