前面面试的文章中我们说过一道关于宏任务和微任务的题:

setTimeout(function(){console.log('1')
});new Promise(function(resolve){console.log('2');resolve();
}).then(function(){console.log('3')
});console.log('4')

试问一下上面代码的执行顺序是啥?

有小伙伴可能会答:2,4,1,3

估摸着是这么想的:我难道不知道js是一行一行执行的,setTimeout是异步,所以先放后面;往下走,执行了console.log(2),.then()是异步的,放在后面;走了console.log(4);再去异步队列里走,先是console.log(1);再是console.log(3)。

But,事实真是如此吗?我有点慌,于是我粘贴到浏览器去瞅两眼:

我擦嘞,居然是2,4,3,1!我简直不敢相信!

带着困惑的我,只能去好好研究研究JavaScript的运行机制了!

1、关于JavaScript

JavaScript是一门单线程语言,即一次只能完成一个任务,若有多个任务要执行,则必须排队按照队列来执行(前一个任务完成,再执行下一个任务)。

2、JavaScript事件循环

既然js是单线程,那就像只有一个窗口的食堂,学生需要排队一个一个打饭,同理js任务也要一个一个顺序执行。这种模式执行简单,但随着日后的需求,事务,请求增多,这种单线程模式执行效率必定低下。只要有一个任务执行消耗了很长时间,在这个时间里后面的任务无法执行。

常见的有新闻包含的超清图片加载很慢,难道我们的网页要一直卡着直到图片完全显示出来?为了解决这个问题,JavaScript语言将任务执行模式分成同步和异步:

同步模式:就是上面所说的一种执行模式,后一个任务等待前一个任务结束,然后再执行,程序的执行顺序与任务的排列顺序是一致的、同步的。

异步模式:就是每一个任务有一个或多个回调函数(callback),前一个任务结束后,不是执行后一个任务,而是执行回调函数,后一个任务则是不等前一个任务结束就执行,所以程序的执行顺序与任务的排列顺序是不一致的、异步的。

导图要表达的内容用文字来表述的话:

  • 同步和异步任务分别进入不同的执行"场所",同步的进入主线程,异步的进入Event Table并注册函数。
  • 当指定的事情完成时,Event Table会将这个函数移入Event Queue。
  • 主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行。
  • 上述过程会不断重复,也就是常说的Event Loop(事件循环)。

再配上代码表达:

let data = [];
$.ajax({url:blog.csdn.net,data:data,success:() => {console.log('发送成功!');}
})
console.log('代码执行结束');

上面是一段简易的ajax请求代码:

  • ajax进入Event Table,注册回调函数success
  • 执行console.log('代码执行结束')
  • ajax事件完成,回调函数success进入Event Queue。
  • 主线程从Event Queue读取回调函数success并执行。

相信通过上面的文字和代码,你已经对js的执行顺序有了初步了解。然而这也是为什么会有小伙伴回答2,4,1,3的原因。

然而实际上,异步队列里是还有门道的,我们那道面试题,setTimeout和promise的.then()都在异步队列了!接下来,讲讲那些门道(宏任务和微任务)。

3、宏任务和微任务

每个人的理解方式不同,因为宏任务和微任务并不是标准,但执行的顺序在js中是大一统了的。

宏任务

# 浏览器 Node
<script>整体代码
setTimeout
setInterval
setImmediate x
requestAnimationFrame x
Ajax
DOM事件

微任务

# 浏览器 Node
process.nextTick x
MutationObserver x
Promise.then catch finally

宏任务包括:<script>整体代码、setTimeout、setInterval、setImmediate、Ajax、DOM事件
微任务:process.nextTick、MutationObserver、Promise.then catch finally

process.nextTick差异太大,不同的node执行不统一,不做标准
**微任务比宏任务的执行时间要早**

Tip:有些人喜欢将<script>整体代码放在宏任务里,但我个人不喜欢,在我这里它只是第一执行的主线程,我个人是将宏任务和微任务都归类到异步任务里!

我们再来看看那道面试题:

//回调才是异步任务
setTimeout(function(){//宏任务console.log('1')
});new Promise(function(resolve){console.log('2');//同步主线程resolve();
}).then(function(){//微任务console.log('3')
});console.log('4')//同步主线程

2:同步中的第一个,故第一

4:同步中的第二个,故第二

3:异步中的微任务,故第三

1:异步中的宏任务,故第二

因此:2,4,3,1的结果就出来了! 

除此我们来拓展一下:

setTimeout(() => {//宏任务队列1console.log('1');//宏任务队1的任务1setTimeout(() => {//宏任务队列3(宏任务队列1中的宏任务)console.log('2')}, 0)new Promise(resolve => {resolve()console.log('3')//宏任务队列1的任务2}).then(() => {//宏任务队列1中的微任务console.log('4')})}, 0)setTimeout(() => {//宏任务队列2console.log('5')
}, 0)console.log('6')//同步主线程

执行整体代码(宏任务)console.log('6') >> 宏任务队列1、宏任务队列2位异步(依次执行)

宏任务队列1:=>

console.log('1')

console.log('3')

console.log('4')//宏任务中的微任务

剩下的不会先执行,因为是宏任务中的宏任务(console.log(2)) ,要被继续丢进任务队列后

宏任务队列2:=>

console.log('5')

宏任务队列1中的宏任务3:=>

console.log('2')

以上代码会怎么输出呢?

4、拓展宏任务微任务

上面出了复杂的题,小伙伴们不妨可以想一想,这种复杂情况,一个套一个的该怎么执行呢?

整体代码:

  • 6:第一个同步主线程,故第一

script整体代码里没有微任务故直接执行宏任务=>

宏任务队列:

  • 宏任务队列1

任务1:console.log(1)

任务2:console.log(3)

宏任务队列1中的微任务:console.log(4)

宏任务队列3:因他是宏任务队列1中的宏任务,所以被丢进了任务队列最后,我们先看宏任务队列1同级的是否还有宏任务,有就先执行同级的,没有才可以执行宏任务队列3!故最后

  • 宏任务队列2

console.log(5)

所以输出的结果是什么?是6,1,3,4,5,2

经过验证,结果正确!


5、总结

实际上你只需要知道拓展之前的,毕竟拓展后的确实比较复杂,需要一定的理解能力,他可以三层,可以四层等....我不信你会跟这题目一样写代码,这不是憨批是什么

❤️一起谈一谈js中的宏任务和微任务!相关推荐

  1. php编码 js解码,浅谈php和js中json的编码和解码

    php中 1)编码 $jsonstr = json_encode($array) 2)解码 $arr = json_decode($jsonstr) echo json_encode("中文 ...

  2. js 编码 php 解码,浅谈php和js中json的编码和解码

    php中 1)编码 $jsonStr = json_encode($array) 2)解码 $arr = json_decode($jsonStr) echo json_encode("中文 ...

  3. 事件循环中的宏任务和微任务执行顺序

    事件循环中的宏任务和微任务执行顺序 先来了解一下事件循环.宏任务.微任务和Promise 1.事件循环(Event Loop)运行机制 执行一个宏任务(栈中没有就从事件队列中获取) 执行过程中如果遇到 ...

  4. 【JS】JavaScript中的宏任务和微任务

    目录 概念 宏任务 微任务 运行机制 总结 js是一门单线程语言,所以它本身是不可能异步的,但是js的宿主环境(比如浏览器.node)是多线程,宿主环境通过某种方式(事件驱动)使得js具备了异步的属性 ...

  5. JS事件循环中的宏任务和微任务执行顺序

    1. 宏任务和微任务事件 其中微任务的优先级高于宏任务,括号内为事件运行环境 宏任务 微任务 I/O事件/onClick点击事件 process.netTick (Node) setTimeout N ...

  6. JavaScript中的宏任务和微任务

    先来个例子 如果能很快知道执行的顺序结果,那么说明你对这块的内容理解非常深刻. <div class="parent" data-spm="2.2.2.2" ...

  7. js 中的 Event Loop 以及 宏任务 与 微任务

    目录 前言 1.JS 的 执行引擎 与 执行环境 2.js 是单线程的 一.事件循环(Event Loop) 二.任务队列 三.宏任务 与 微任务 1.宏任务 2.微任务 3.宏任务与微任务的运行机制 ...

  8. 浅谈JS中常见的问题(三)

    往期文章目录 浅谈JS中常见的问题(一) 浅谈JS中常见的问题(二) JS知识总结 往期文章目录 前言 11. 同步和异步的区别 12. JS 判断变量类型的几种方法 13. 如何阻止事件冒泡与默认事 ...

  9. 一篇文章理解JS中同步任务和异步任务以及宏任务与微任务的原理和执行机制

    前言: javascript是一种单线程编程语言, 一般来说它的执行顺序是按照从上到下执行,但是有些特殊情况则会改变这样的执行顺序,我们需要理解和掌握其中的原理,需要了解同步任务和异步任务以及宏任务和 ...

最新文章

  1. OpenCV中常用到的轮廓处理函数汇总
  2. mxnet优化器 SGD_GC
  3. NLPIR大数据处理技术实现多种类智能挖掘
  4. .net core 文件流保存图片_使用JSDelivr加速Github、博客文件
  5. 【UAV】高度控制代码分析
  6. makefile中变量有哪些?
  7. etcd mysql集群_Etcd单节点扩容为三节点集群
  8. java 8 lambda 排序_Java8 用Lambda表达式给List集合排序的实现
  9. Beyond Compare中插入表格数据的教程
  10. 栈和队列之生成窗口最大值数组
  11. 汇编语言笔记(三): 标志寄存器
  12. Android数据储存之SharedPreferences总结
  13. 职业生涯设计的10点忠告
  14. Find password cracker in 11g
  15. 手把手FFmpeg入门——视频解码+解封装
  16. 中科方德桌面操作系统_兆芯CPU与中科方德新版桌面/服务器操作系统完成互认证...
  17. 计算一个文件下的所有视频总时长
  18. LM358资料及引脚图
  19. Facebook受邀者的邮箱地址披露
  20. 算法-经典趣题-青蛙过河

热门文章

  1. 微博消息分析-大数据项目
  2. 李进良丁守谦论道4G:决不应三国纷争
  3. (转载)【笨木头Lua专栏】基础补充18:Lua的模块编写与module函数
  4. ssm保险办理系统毕业设计源码012232
  5. http://www.dewen.net.cn/q/16042/jquery fadeIn和fadeOut问题
  6. [论文笔记]Seed,Expend and Constrain
  7. Power PMAC运动控制器 —— 学习笔记1
  8. Qt QImage与OpenCV Mat转换
  9. Keepalive User Guide for gRpc Core(and dependents)
  10. 电磁阀安装和使用事项