JavaScript 没有宏任务和微任务

在 JavaScript 中,宏任务和微任务的概念是建立在事件循环机制之上的一种抽象描述,用于帮助理解异步任务的执行顺序和优先级。实际上,JavaScript 中并没有宏任务和微任务这两个直接的概念,而是通过事件循环 (Event Loop) 来实现异步任务的调度和执行。

事件循环机制

JavaScript 是单线程语言,这意味着它一次只能执行一个任务。然而,为了处理用户的输入、网络请求等异步操作,JavaScript 引擎采用了事件循环机制来模拟并发执行。事件循环机制负责管理和调度异步任务的执行,它会不断地从事件队列中取出任务执行,直至所有任务执行完毕。

事件循环是一个不断循环的过程,它包含以下步骤:

  1. 检查是否有待处理的宏任务。
  2. 如果有,则执行该宏任务。
  3. 在宏任务执行期间,如果遇到微任务,则将微任务添加到微任务队列中。
  4. 宏任务执行完毕后,检查微任务队列,并执行队列中的所有微任务。
  5. 渲染页面。

宏任务与微任务的执行时机

宏任务 (Macrotask) 代表着一组任务,每个宏任务会在当前事件循环中执行完毕后执行。常见的宏任务包括定时器回调函数、DOM 事件处理函数、网络请求回调函数等。典型的宏任务包括:

  • setTimeout() 和 setInterval()
  • 脚本执行
  • DOM 事件处理程序
  • Ajax 请求

微任务 (Microtask) 则代表着一组需要尽快执行的任务,每个微任务会在当前宏任务执行完毕后立即执行。微任务的优先级高于宏任务,可以确保在宏任务执行完毕前立即执行。常见的微任务包括:

  • Promise.then()
  • MutationObserver
  • requestAnimationFrame()

执行顺序和优先级

微任务的优先级高于宏任务。这意味着在事件循环中,微任务会在宏任务之前执行。

示例和 Demo

下面是一个简单的示例来演示宏任务和微任务的执行时机:

javascript 复制代码
console.log('Start');

setTimeout(() => {
  console.log('宏任务');
}, 0);

Promise.resolve().then(() => {
  console.log('微任务');
});

console.log('End');

在浏览器的控制台中运行上述代码,你会看到以下输出:

Linux 复制代码
Start
End
微任务
宏任务

解释:

  • 首先,console.log('Start')console.log('End') 会立即执行,因为它们是同步代码。
  • 然后,Promise.resolve().then(() => { console.log('微任务'); }) 会被添加到微任务队列中,因为它是一个微任务。
  • 接着,setTimeout(() => { console.log('宏任务'); }, 0) 会被添加到宏任务队列中,因为它是一个宏任务。
  • 浏览器会执行事件循环。
  • 在事件循环的第一个步骤中,浏览器会检查是否有待处理的宏任务。发现有,则执行 setTimeout() 函数,输出 宏任务
  • setTimeout() 函数执行之前,浏览器会检查微任务队列。发现有,则执行 Promise.then() 函数,输出 微任务
  • 最后,浏览器会渲染页面。

注意

这说明微任务(Promise)会在宏任务(setTimeout)之前执行。

总结

虽然在 JavaScript 的规范中并没有直接定义宏任务和微任务的概念,但它们是在事件循环机制中的一种抽象描述,有助于我们理解异步任务的执行顺序和优先级。通过合理地利用宏任务和微任务,我们可以更好地管理和优化 JavaScript 代码的执行。

进阶(面试可能加分哦)

事件循环的更多细节

  • 事件循环不止一个,浏览器通常会维护多个事件循环,用于不同的任务类型,例如 DOM 事件、网络请求等。
  • 微任务队列也可能不止一个,不同的微任务队列可能具有不同的优先级。

相关 API

  • setTimeout()setInterval():用于延迟执行任务。
  • Promise:用于处理异步操作。
  • MutationObserver:用于监听 DOM 元素的变化。
  • requestAnimationFrame():用于在浏览器下一次重绘之前执行任务。

参考资料

作为了解

不同浏览器版本和不同的 JavaScript 引擎可能会对事件循环机制的实现细节有所不同。 尽管在 ECMAScript 标准中规定了事件循环的基本机制,但实际上每个浏览器厂商和 JavaScript 引擎开发者都可能根据自己的需求和优化策略进行调整和改进。

这些差异可能会涉及到宏任务和微任务的处理顺序、微任务与宏任务之间的关系、任务队列的管理方式等方面。因此,在编写依赖于事件循环机制的代码时,需要考虑到这些差异,以确保代码在不同环境下的兼容性和稳定性。

通常情况下,浏览器厂商会遵循 ECMAScript 标准,并尽可能保持与其他浏览器的一致性。

相关推荐
yqcoder4 分钟前
NPM 包管理问题汇总
前端·npm·node.js
程序菜鸟营10 分钟前
nvm安装详细教程(安装nvm、node、npm、cnpm、yarn及环境变量配置)
前端·npm·node.js
bsr198321 分钟前
前端路由的hash模式和history模式
前端·history·hash·路由模式
杨过姑父1 小时前
ES6 简单练习笔记--变量申明
前端·笔记·es6
2401_897916841 小时前
2018 秋招 百度二轮面试---血淋淋的经历写实
面试·职场和发展
Jacob程序员1 小时前
leaflet绘制室内平面图
android·开发语言·javascript
Sunny_lxm1 小时前
<keep-alive> <component ></component> </keep-alive>缓存的组件实现组件,实现组件切换时每次都执行指定方法
前端·缓存·component·active
eguid_11 小时前
JavaScript图像处理,常用图像边缘检测算法简单介绍说明
javascript·图像处理·算法·计算机视觉
sunly_2 小时前
Flutter:自定义Tab切换,订单列表页tab,tab吸顶
开发语言·javascript·flutter
咔咔库奇2 小时前
【TypeScript】命名空间、模块、声明文件
前端·javascript·typescript