js中的宏任务与微任务
如果你已经知道了js中存在宏任务和微任务,那么你一定已经了解过promise了。因为在js中promise是微任务的一个入口。
先来看一道题:
setTimeout(function(){
console.log('setTimeout')
});
new Promise(function(resolve, reject){
console.log('pormise body');
resolve();
}).then(function(){
console.log('promise then')
});
console.log('main');
这题的答案是:
promise body
main
promise then
setTimeout
promise body出现在第一行一点也不意外,意外的是,setTimeout出现在了promise then的后边。
setTimeout和promise then都是异步调用,setTimeout又定义在promise之前,如果没有意外,应该是先输出setTimeout才对,但这里却恰恰相反。
这里涉及到的知识点,就是宏任务与微任务了。标记一下上边的代码:
setTimeout(function(){ // 同步代码,语句1
console.log('setTimeout') // 宏任务,语句2
});
new Promise(function(resolve, reject){
console.log('pormise body'); // 同步代码,语句3
resolve(); // 同步代码,语句4
}).then(function(){
console.log('promise then') // 微任务,语句5
});
console.log('main'); // 同步代码,语句6
那么他们运行的规则是怎样的呢?
原来,宏任务与微任务,都各自有一个调用队列(先进先出)。
遇到宏任务,微任务,则将他们推入各自的调用队列。需要注意的是,同步代码也是宏任务。
宏任务执行完一个,则去清空微任务队列,微任务清空后再去执行下一个宏任务。
这个过程颇像去医院诊室排队看大夫的情景:
如果有一个病人A叫到号以后,又被大夫安排先去做检查,那么做完检查以后病人A回到诊室门口,可以直接等待当前正在看病的病人B与大夫交谈结束后,将检查结果交给大夫,而不用再次排队。
我们来把上面的代码一行一行解读一下:
首先定义两个队列,宏任务队列:MacroQqueue, 微任务队列: MicroQueue
第一步,先按同步代码顺序运行
同步代码,语句1: 添加一个宏任务,将语句2推入MacroQueue。 // MacroQueue: [{task: 语句2}]
同步代码,语句3: 打印promise body
同步代码,语句4: 添加一个微任务,将语句5推入MicroQueue。 // MicroQueue: [{task: 语句5}]
同步代码,语句6: 打印main。 // 同步代码(宏任务)完成
第二步,开始清空微任务队列
微任务: 语句5,从MicroQueue跳出,打印promise then。 // 微任务队列全部清空
第三步,开始清空宏任务队列
宏任务:语句2,从MacroQqueue跳出,打印setTimeout // 宏任务队列全部清空
第四步:开始清空微任务队列
队列为空...
一轮循环完成。开始下一轮,如此循环下去。
通过上面的讲解,大家应该能对宏任务,微任务的运行机制有了一定的了解了吧。那么都有哪些常见的宏任务与微任务呢?
请看下表:
| 宏任务 | 浏览器 | nodejs |
|---|---|---|
| 同步代码 | ✅ | ✅ |
| I/O | ✅ | ✅ |
| setTimeout | ✅ | ✅ |
| setInterval | ✅ | ✅ |
| setImmediate | ❌ | ✅ |
| requestAnimationFrame | ✅ | ❌ |
| 微任务 | 浏览器 | nodejs |
|---|---|---|
| process.nextTick | ❌ | ✅ |
| MutationObserver | ✅ | ❌ |
| Promise (async/await) | ✅ | ✅ |
好了,我们来一道复杂一点的题练练手:
console.log('sync statement 1');
Promise.resolve().then(function() {
console.log('micro task 1');
setTimeout(function() {
console.log('macro task 1');
}, 0);
}).then(function() {
console.log('micro task 2');
});
setTimeout(function() {
console.log('macro task 2')
Promise.resolve().then(function(){
console.log('micro task 3');
})
}, 0)
console.log('sync statement 2');
//输出:
// sync statement 1
// sync statement 2
// micro task 1
// micro task 2
// macro task 2
// micro task 3
// macro task 1
标注一下方便大家分析:
console.log('sync statement 1'); // 同步代码,语句1
Promise.resolve().then(function() { // 同步代码,语句2,注册了一个微任务
console.log('micro task 1'); // 微任务,语句3
setTimeout(function() { // 微任务,语句4,同时注册了一个宏任务
console.log('macro task 1'); // 宏任务,语句5
}, 0);
}).then(function() {
console.log('micro task 2'); // 微任务,语句6
});
setTimeout(function() { // 同步代码,语句7
console.log('macro task 2') // 宏任务,语句8
Promise.resolve().then(function(){ // 宏任务,语句9,同时注册了一个微任务
console.log('micro task 3'); // 微任务,语句10
})
}, 0)
console.log('sync statement 2'); // 同步代码,语句11
js中的宏任务与微任务的更多相关文章
- javascript中的宏任务和微任务(一)
一.宏任务和微任务有哪些 宏任务:setTimeout,setInterval,ajax,dom,宏任务是由浏览器提供的 微任务:promise,async/await,微任务是由es6提供的 二.微 ...
- javascript中的宏任务和微任务(二)
js事件轮询执行顺序总结: 1)所有的同步任务都在主线程上执行,行成一个执行栈. 2)除了主线程之外,还存在一个任务列队,只要异步任务有了运行结果,就在任务列队中植入一个时间标记. 3)主线程完成所有 ...
- JS异步之宏队列与微队列
1. 原理图 2. 说明 JS 中用来存储待执行回调函数的队列包含 2 个不同特定的列队 宏列队:用来保存待执行的宏任务(回调),比如:定时器回调.DOM 事件回调.ajax 回调 微列队:用来保存待 ...
- JS中EventLoop、宏任务与微任务的个人理解
为什么要EventLoop? JS 作为浏览器脚本语言,为了避免复杂的同步问题(例如用户操作事件以及操作DOM),这就决定了被设计成单线程语言,而且也将会一直保持是单线程的.而在单线程中若是遇到了耗时 ...
- JavaScript同步模式,异步模式及宏任务,微任务队列
首先JavaScript是单线程的语言,也就是说JS执行环境中,负责执行代码的线程只有一个.一次只能执行一个任务,如果有多个任务的话, 就要排队,然后依次执行,优点就是更安全,更简单.缺点就是遇到耗时 ...
- JS中的执行机制(setTimeout、setInterval、promise、宏任务、微任务)
1.执行机制 JS 是单线程的,处理 JS 任务(程序)只能一个一个顺序执行,所以 JS 中就把任务分为了同步任务和异步任务.同步的进入主线程先执行,异步的进入Event Table并注册函数,当指定 ...
- js的事件循环机制:同步与异步任务(setTimeout,setInterval)宏任务,微任务(Promise,process.nextTick)
javascript是单线程,一切javascript版的"多线程"都是用单线程模拟出来的,通过事件循环(event loop)实现的异步. javascript事件循环 事件循环 ...
- js 宏任务和微任务
.宏任务(macrotask )和微任务(microtask ) macrotask 和 microtask 表示异步任务的两种分类. 在挂起任务时,JS 引擎会将所有任务按照类别分到这两个队列中,首 ...
- js 同步 异步 宏任务 微任务 文章分享
分享一篇 写的很好的 宏任务 微任务 同步异步的文章 文章原地址: https://juejin.im/post/59e85eebf265da430d571f89 这一次,彻底弄懂 JavaScri ...
随机推荐
- 如何做seo优化才能获取搜索引擎排名?
现在网络上有很多网站,但是排名和流量都不理想,所以很多企业会很苦恼.所以我们经常思考如何使网站被搜索引擎喜欢,被用户喜欢,有一个良好的排名和流量? 在这个鱼龙混杂的网络中,seo优化实际上是seo网站 ...
- Spring Cloud gateway 五 Sentinel整合
微服务当前这么火爆的程度,如果不能学会一种微服务框架技术.怎么能升职加薪,增加简历的筹码?spring cloud 和 Dubbo 需要单独学习.说没有时间?没有精力?要学俩个框架?而Spring C ...
- 深入理解java虚拟机系列初篇(一):为什么要学习JVM?
前言 本来想着关于写JVM这个专栏,直接写知识点干货的,但是想着还是有必要开篇讲一下为什么要学习JVM,这样的话让一些学习者心里有点底的感觉比较好... 原因一:面试 不得不说,随着互联网门槛越来越高 ...
- ASP.NET Core 3 使用原生 依赖注入 集成 AspectCore ,实现 AOP 功能
在NETCORE中可以使用AOP的方式有很多很多,包括国内优秀的开源框架asp.netcore同样可以实现AOP编程模式. IOC方面,个人喜欢net core 3自带的DI,因为他注册服务简洁优 ...
- MySQL如何永久解决由dos编码格式导致MySQ的显示乱码
MySQL如何永久解决由dos编码格式导致MySQ的显示乱码 Ⅰ.新建文件 changeCode.txt Ⅱ.粘贴下面代码(作用:将默认的GBK(936)修改为UTF-8(65001)) Window ...
- 在校生如何面向面试地学习Java
最近我在博客园里,看到不少在校的同学在学java,而且,在我最近举办的一次直播活动中,也有不少在校生同学来提问,java该怎么学. 对于那些已经工作的同学,哪怕才工作不久,毕竟也能从项目实践里总结和探 ...
- 【前端知识体系-CSS相关】CSS特效实现之Transition和Transform对比
CSS效果 1.使用div绘制图形(三角形)? <!DOCTYPE html> <html lang="en"> <head> <meta ...
- 命令序列 ; & && ||
; 从左到右依次被执行,返回最后一个命令的执行状态 & 该命令将在后台被执行,即在子bash中执行(或ctrl+z,bg, jobs,bg 命令号)(变量$!.$one.$two.$three ...
- Unix, Linux以及NT内核和它们各自衍生的系统关系图
- Charles 笔记
一. Charles工作原理 本质就是一个http抓包分析工具,在工作的时候将charles设置成代理服务器,所有网络请求都会经过Charles,这样就实现了网络封包的截取和分析. 主要功能 截取ht ...