Web前端入门第 68 问:JavaScript 事件循环机制中的微任务与宏任务
JS 是单线程语言。这句话对不对?
按照目前的情况来看,JS 自从支持了 Web Worker 之后,就不再是单线程语言了,但 Worker 的工作线程与主线程有区别,在 Worker 的工作线程中无法直接操作 DOM、window 对象或大多数浏览器 API(如 localStorage),Worker 的全局对象也不再是 window 对象,而是 self。
Worker 中的事件循环与主线程相互独立,互不影响,但执行顺序还是得遵循 JS 的语法规则。
宏任务
宏任务表示执行时间较长的任务,在每次时间循环时只会执行一个宏任务,执行完毕后处理微任务队列,所有微任务都执行完毕后进入下一个宏任务。
JS 常见宏任务类型:
- 定时器任务:setTimeout / setInterval
- DOM 事件回调(如 click、scroll)
- I/O 操作(如文件读取、网络请求)
- 浏览器用于执行动画的方法
requestAnimationFrame,执行时机与渲染相关 - Node.js 环境的
setImmediate - script 标签内主线程的同步代码(整体作为一个宏任务)
微任务
微任务表示更轻量的异步任务,当宏任务执行完毕之后立即执行。
JS 常见微任务类型:
Promise.then()/Promise.catch()/Promise.finally()- 浏览器监听 DOM 变化的 API 对象,比如:
MutationObserver - 手动添加微任务API方法:
queueMicrotask() - nodejs 中的
process.nextTick()
代码解析
看这么一段代码:
(function() {
console.log(1)
setTimeout(() => { console.log(2); });
queueMicrotask(() => console.log(3))
new Promise(resolve => {
console.log(4);
setTimeout(() => {
resolve();
console.log(5);
}, 0);
Promise.resolve().then(() => console.log(6));
console.log(7);
}).then(() => {
console.log(8);
Promise.resolve().then(() => console.log(9));
});
console.log(10);
})();
分析代码:
(function() {
console.log(1) // 同步任务
setTimeout(() => { console.log(2); });
queueMicrotask(() => console.log(3))
new Promise(resolve => {
console.log(4); // 同步任务
setTimeout(() => { // 宏任务
resolve(); // 宏任务的同步任务
console.log(5); // 宏任务中的同步任务
}, 0);
Promise.resolve().then(() => console.log(6)); // 微任务
console.log(7); // 同步任务
}).then(() => { // 微任务
console.log(8); // 微任务中的同步任务
Promise.resolve().then(() => console.log(9)); // 微任务中的微任务
});
console.log(10); // 同步任务
})();
第一轮
首先同步代码的宏任务优先级最高,不管微任务还是宏任务,同步代码都会先执行。
所以上面代码会优先执行:
console.log(1)
console.log(4);
console.log(7);
console.log(10);
接着开始处理微任务:
queueMicrotask(() => console.log(3))
Promise.resolve().then(() => console.log(6));
微任务处理完,开始执行下一轮宏任务。
第二轮
这一轮中的宏任务只有一个 setTimeout,执行完之后由于没有微任务队列,所以直接执行下一轮宏任务。
setTimeout(() => { console.log(2); });
第三轮
这一轮的宏任务中有同步代码。
setTimeout(() => { // 宏任务
resolve(); // 宏任务的同步任务
console.log(5); // 宏任务中的同步任务
}, 0);
在执行完 resolve() 之后,会将 Promise.then 的回调函数放入微任务队列中,所以在宏任务执行完之后会开始微任务:
then(() => { // 微任务
console.log(8); // 微任务中的同步任务
Promise.resolve().then(() => console.log(9)); // 微任务中的微任务
})
最终的打印顺序
1
4
7
10
3
6
2
5
8
9
执行流程图
JS 代码逐行执行,在遇到宏任务时,整个代码块丢到宏任务队列,在遇到微任务时,将微任务丢到本次事件循环中的微任务队列,本次事件循环执行完之后,再执行微任务队列中的任务,微任务执行完之后开始下一个宏任务执行。
JS 代码执行机制:

宏任务执行机制:

写在最后
JS 中的代码执行流程永远都是事件循环机制,这是 JS 的任务调度核心,理解事件循环机制,才能在开发中游刃有余~~
Web前端入门第 68 问:JavaScript 事件循环机制中的微任务与宏任务的更多相关文章
- 一篇文章图文并茂地带你轻松学完 JavaScript 事件循环机制(event loop)
JavaScript 事件循环机制 (event loop) 本篇文章已经默认你有了基础的 ES6 和 javascript语法 知识. 本篇文章比较细致,如果已经对同步异步,单线程等概念比较熟悉的读 ...
- 深入理解JavaScript事件循环机制
前言 众所周知,JavaScript 是一门单线程语言,虽然在 html5 中提出了 Web-Worker ,但这并未改变 JavaScript 是单线程这一核心.可看HTML规范中的这段话: To ...
- 深入浅出Javascript事件循环机制
一.JS单线程.异步.同步概念 众所周知,JS是单线程(如果一个线程删DOM,一个线程增DOM,浏览器傻逼了-所以只能单着了),虽然有webworker酱紫的多线程出现,但也是在主线程的控制下.web ...
- javascript事件循环机制 浅尝手记
引入 众所周知Javascript是一个单线程的机制,虽然可以依托多线程的浏览器实现页面如何实现页面复杂的渲染.事件响应,但仍不会改变其单线程的本质:所以对于js的事件循环机制的了解是一个前端人员的必 ...
- 浏览器中的JavaScript事件循环机制
浏览器的事件循环机制是HTML中定义的规范. JavaScript有一个主线程和调用栈,所有的任务都会被放到调用栈等待主线程执行. JS调用栈 是一种先进后出的数据结构.当函数被调用时,会被添加到栈中 ...
- javaScript 事件循环机制
JavaScript是单线程的编程语言,只能同一时间内做一件事.但是在遇到异步事件的时候,js线程并没有阻塞,还会继续执行,这就是因为JS有事件循环机制. 事件循环流程总结 主线程开始执行一段代码, ...
- JavaScript事件循环机制
事件循环 事件循环不仅仅包含事件队列,而是具有至少两个队列,除了事件,还要保持浏览器执行的其他操作.这些操作被称为任务,并且分为两类:宏任务(或通常称为任务)和微任务. 单次循环迭代中,最多处理一个宏 ...
- JS JavaScript事件循环机制
区分进程和线程 进程是cpu资源分配的最小单位(系统会给它分配内存) 不同的进程之间是可以同学的,如管道.FIFO(命名管道).消息队列 一个进程里有单个或多个线程 浏览器是多进程的,因为系统给它的进 ...
- 一道面试题引发对javascript事件循环机制(Event Loop)的 思考(这里讨论针对浏览器)
- JS浏览器事件循环机制
文章来自我的 github 博客,包括技术输出和学习笔记,欢迎star. 先来明白些概念性内容. 进程.线程 进程是系统分配的独立资源,是 CPU 资源分配的基本单位,进程是由一个或者多个线程组成的. ...
随机推荐
- centos7 挂载未分配的硬盘空间 (测试可用)
=============================================== 2019/7/28_第1次修改 ccb_warlock == ...
- HTML5 给网站添加图标
1.首先将图标上传到对应的目录下 2.在网页的index.html,添加已下代码到<head>标签里 <link rel="icon" href="i_ ...
- 【Python】PDF文档导出指定章节为TXT
PDF文档导出指定章节为TXT 需求 要导出3000多个pdf文档的特定章节内容为txt格式(pdf文字可复制). 解决 导出PDF 查了一下Python操作PDF文档的方法,主要是通过3个库,PyP ...
- 【FAQ】HarmonyOS SDK 闭源开放能力 —Push Kit(12)
1.问题描述: pushdeviceid的长度是固定的吗? 解决方案: 在鸿蒙系统中,设备ID的长度是固定的. 2.问题描述: 通过REST API三方推送IM类消息,如何实现应用处于前台时不展示三方 ...
- S7.Net与西门子PLC通讯——纯新手必看
前言 本文档适合从未接触过PLC的.NET开发程序员入门查看.(其实看完了之后,PLC开发也就那样) PLC通讯入门比较难,需要关注的细节比较多.一边学习一边举一反三多思考,一定要自己创建Demo跟 ...
- tomcat非root用户启动
部署远程服务器时候, 基本都是用root账户登录, 习惯上会直接使用root启动tomcat. 这样其实是有风险的, 黑客获取的权限即容器的权限, 如果容器运行权限就很高,被攻破黑客即可获取很高的权限 ...
- 详细介绍FutureTask类
一.详细介绍FutureTask类 FutureTask 未来将要执行的任务对象,继承 Runnable.Future 接口,用于包装 Callable 对象,实现任务的提交 public stati ...
- Linux防火墙操作指令
firewall-cmd --list-ports # 查看开放的端口号 firewall-cmd --zone=public --add-port=8888/tcp --permanent # 开放 ...
- jstree上手文档 [初始化时默认选中、全部展开、获取实例的数据等问题]
jstree官网:https://www.jstree.com/ ------------------- 实例化tree .jstree() 默认样式: var container = $('#xxx ...
- 题解:CF280B Maximum Xor Secondary
由于正求次大值比较困难,不如逆向思考. 由次大值来找最大值,即对于每个 iii,找到一个 jjj,满足 j<ij<ij<i 并且 ai<aja_i<a_jai<a ...