一文搞懂JS系列(六)之微任务与宏任务,Event Loop

写在最前面:这是我写的一个一文搞懂JS系列专题。文章清晰易懂,会将会将关联的只是串联在一起,形成自己独立的知识脉络整个合集读完相信你也一定会有所收获。写作不易,希望您能给我点个赞

合集地址:一文搞懂JS系列专题

概览

  • 食用时间: 10-15分钟

  • 难度: 简单,别跑,看完再走

  • 食用价值: JS单线程,搞懂同步异步,微任务与宏任务,Event Loop,文末一题

单线程的JS

大家应该都知道 JS 有一个特性,在刚开始学习的时候应该就知道了,那就是 JS单线程的。

那么,为什么 JS 是单线程的呢,明明多线程能提升效率啊。

其实,这个与它的本身用途也有关系, JS 的主要用途是与用户互动,以及操作 DOM 。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定 JS 同时有两个线程,一个线程在某个 DOM 节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?

单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。

如果排队是因为计算量大, CPU 忙不过来,倒也算了,但是很多时候 CPU 是闲着的,因为IO设备(输入输出设备)很慢(比如Ajax操作从网络读取数据),不得不等着结果出来,再往下执行。

JavaScript语言的设计者意识到,这时主线程完全可以不管IO设备,挂起处于等待中的任务,先运行排在后面的任务。等到IO设备返回了结果,再回过头,把挂起的任务继续执行下去。这就有了之后的同步任务和异步任务

于是,所有任务可以分成两种,一种是同步任务( synchronous ),另一种是异步任务( asynchronous )。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入”任务队列”(task queue)的任务,只有”任务队列”通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。

所以,是单线程的出现,才引发了同步和异步的出现,接下来,让我们来引入一个生活中的例子,方便大家更好地理解同步和异步

参考于阮一峰 JavaScript 运行机制详解:再谈Event Loop

现实生活中的同步与异步

就比方说我们平时吃KFC,我们都要去收银台排队,(别跟我说扫码点餐!),假设我们点了一份炸鸡 + 付款一分钟,取餐需要五分钟,这个时候店员说,按照我们店里的规定,我们只能一个接一个的服务客户,后面的客户必须等当前这个客户取完餐,才能换下一个客户点餐,而这种情况,那就是所谓的同步,就是按顺序执行,一件事情做完了,才能做下一件事情。

但是结果是很明显的,这种接客方式也未免效率太低了,那KFC估计也支撑不到今天就已经倒闭了。

为了提升自己的服务效率,后来,KFC推出了 点餐区 以及 取餐区 。在你付款完成以后,给你一张取餐小票,就可以从收银台的队列中出去啦,让下一个客户赶紧点餐,而你只需要等前台通知你,你要的套餐做好啦,快来取餐区取餐啦。

JS中的同步与异步

  • 同步

    任务从上往下按顺序执行,后一个任务必须等待前一个任务执行完(后一个点餐的人必须要等前一个人取完餐)

  • 异步

    前一个任务还没执行完(前一个人还没取完餐), 也没关系,直接执行下一个任务(让下一个客户点餐),等到前台通知取餐,在执行(取餐)

经过同步任务和异步任务的划分,程序的运行效率明显提高了(KFC的接待效率)

微任务与宏任务

上面已经对同步任务和异步任务进行了划分,我们都知道,同步任务就是按顺序执行,从上往下。

那么,异步任务也是有它的执行顺序的,它也是从上往下,但是,异步任务里,对于异步类型还有进一步的划分,那就是接下来我们要讲的微任务宏任务,切记微任务比宏任务先执行

  • 微任务(micro-task

    process.nextTick、Promise、MutationObserver等

  • 宏任务(macro-task

    setTimeout、setInterval、 setImmediate、script(整体代码)、I/O 操作等

值得注意的是, Promise 是有一点特殊性的,因为Promise构造函数中函数体的代码都是立即执行的 , 而 Promise.then()Promise.catch() 属于微任务,也就是 resolve()reject()

对于上面这句话的理解,可以来看下下面的例子

new Promise(function (resolve) {
  console.log(1)
})

上面这段实例代码的 1 ,是直接输出的,属于同步任务,虽然它确实在 Promise

学会如何区分微任务与宏任务之后,我们也就对异步任务的执行顺序划分有了进一步的了解

调用栈

这是最后要介绍的一个角色,也就是真正执行代码,执行任务的地方

Event Loop

  1. 初始状态下,调用栈空。微任务队列空,宏任务队列里有且只有一个 script 脚本(整体代码)。这时首先执行并出队的就是 整体代码

  2. 整体代码作为宏任务进入调用栈,进行同步任务和异步任务的区分

  3. 同步任务直接执行并且在执行完之后出栈,异步任务进行微任务与宏任务的划分,分别被推入进入微任务队列宏任务队列

  4. 等同步任务执行完了(调用栈为空)以后,再处理微任务队列,将微任务队列压入调用栈

  5. 当调用栈中的微任务队列被处理完了(调用栈为空)之后,再将宏任务队列压入调用栈,直至调用栈再一次为空,一次轮回结束

整体的运行流程可以查看下图,红色箭头为主要的执行流程整体代码(宏任务) => 同步任务 => 微任务队列 => 宏任务队列

虽然整体代码确实是一开始作为宏任务执行的,但是,希望大家还是要切记,在异步任务中,微任务队列比宏任务队列先执行(方便记忆)

image

关于这个 Event Loop ,其实涉及了很多的知识点,包括 微任务宏任务调用栈执行上下文同步与异步任务队列

文末一题

console.log(1)

setTimeout(function() {
  console.log(2)
})

new Promise(function (resolve) {
  console.log(3)
  resolve()
}).then(function () {
  console.log(4)
}).then(function() {
  console.log(5)
})

console.log(6)

通过上面的学习,这道题就显得十分简单了,答案就是 1 3 6 4 5 2

不明白的话,可以看看我下面的这一段分析,我们从上往下,将代码抽离成三部分,同步任务,微任务队列以及宏任务队列

  • 同步任务

console.log(1)
console.log(3)
console.log(6)
  • 微任务队列

console.log(4)    //Promise.then()
console.log(5)    //Promise.then()
  • 宏任务队列

console.log(2)    //setTimeout

所以,答案一眼就能看的出来是 1 3 6 4 5 2

目录

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,869评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,716评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,223评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,047评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,089评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,839评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,516评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,410评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,920评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,052评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,179评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,868评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,522评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,070评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,186评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,487评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,162评论 2 356

推荐阅读更多精彩内容