【JS档案揭秘】第二集 Event loop与执行栈
我时常在思考关于JS的很多知识在工作中有什么用?是否只能存在于面试这种理论性的东西中,对于我们的业务和工作,它们又能扮演怎样的角色。以后在JS档案揭秘的每一期里,都会加入我对于业务的思考,让这些知识不再是空中楼阁,而是有实际操作的意义。
业务场景
所有的核心在于执行顺序,它能帮助我们正确判断代码按照怎样的顺序去执行。避免因为执行顺序与预期不一致而导致的bug。如果遇到这种因为执行顺序问题而产生的bug,也能通过event loop分析出正确的执行顺序,定位bug并解决。
关键词解释
执行栈:一个专门用来存放执行代码的栈内存结构,它就像一个容器,也叫做执行的主线程。如果遇到函数,会根据回调关系把回调层级深的函数先推入到执行栈底部执行,其他语句依次推入,当全部执行完了后,会从上到下依次弹出执行代码(也就是“先进后出”),供下一次使用;
宏任务(只针对浏览器环境):宿主环境提供的任务,包括:script代码块,MessageChannel,requestAnimationFrame,setTimeout,setInterval;
微任务(只针对浏览器环境):JS自带的任务,包括promise的then和catch,MutationObserver;
任务队列:由宏任务队列与微任务队列组成;
event loop:又名事件循环,它会不断地去微任务队列里取任务放到执行栈执行,当微任务队列被清空时,才去宏任务队列取任务执行。假如这个宏任务里面碰到了微任务和宏任务,会分别推入到任务队列中,并按照“只有微任务队列清空才执行宏任务”的原则来执行代码;
画图理解

过程叙述
当我们说“浏览器是 JS 的家”时,这句话真正的意思是浏览器提供运行时环境来执行我们的JS代码。
浏览器的主要组件包括JS引擎,事件循环,任务队列和Web APIs。上图的任务队列有一点瑕疵,任务队列应该有两个(宏任务队列与微任务队列)。
JS引擎从堆中取出JS代码并及进行分析。假设是一段或多段script代码,它会被认为是一个或几个宏任务,并推入到web apis中。web apis看到是script代码,就把它推入到宏任务队列中,event loop从宏任务队列取到这一段JS代码,并放入执行栈中执行。
在执行当前宏任务时,每当它遇到一些异步代码,如setTimeout,它又会把它推入到web apis中去执行。当异步代码在Web APIs被执行完后,其回调callback 就被送往任务队列。
event loop不断地监视任务队列(Task Queue),并按它们排队的顺序一次处理一个回调。每当调用栈为空,也就是同步代码执行完毕时,event loop会不断地去微任务队列里取任务放到执行栈执行,当微任务队列被清空时,才去宏任务队列取任务执行。请记住,如果调用栈不是空的,则事件循环不会将任何回调推入执行栈。
例题分析

按照我们之前的理论,首先这里分成两个宏任务,script1和script2。
script1的同步代码先执行,打印111,333。微任务队列推入222,宏任务队列推入444。
此时微任务队列只有222,而宏任务队列为“script2 --- 444”。
所以先清空微任务队列,打印出222,再从宏任务队列中取出script2,推到执行栈中执行。
script2的同步代码先执行,打印555,777。并将666推入微任务队列,888推入宏任务队列。
此时微任务队列只有666,而宏任务队列为“444 --- 888”。
所以先清空微任务队列,打印出666,再从宏任务队列依次取出444和888,并推到执行栈中执行。
综上,打印结果如下:

【JS档案揭秘】第二集 Event loop与执行栈的更多相关文章
- Node.js的事件轮询Event Loop原理
Node.js的事件轮询Event Loop原理解释 事件轮询主要是针对事件队列进行轮询,事件生产者将事件排队放入队列中,队列另外一端有一个线程称为事件消费者会不断查询队列中是否有事件,如果有事件,就 ...
- js事件循环机制 (Event Loop)
一.JavaScript是单线程单并发语言 什么是单线程 主程序只有一个线程,即同一时间片断内其只能执行单个任务. 为什么选择单线程? JavaScript的主要用途是与用户互动,以及操作DOM.这决 ...
- js的事件循环(Event Loop)
(本文从掘金小册整理) 首先介绍一下几个概念 进程与线程 相信大家经常会听到 JS 是单线程执行的,但是你是否疑惑过什么是线程? 讲到线程,那么肯定也得说一下进程.本质上来说,两个名词都是 CPU 工 ...
- 对Node.JS的事件轮询(Event Loop)的理解
title: Node.JS的事件轮询(event loop)的理解 categories: 理解 tags: Node JS 机制 当我们知道I/O操作和创建新线程的开销是巨大的! 网站延迟的开销 ...
- 【JS档案揭秘】第一集 内存泄漏与垃圾回收
程序的运行需要内存,对于一些需要持续运行很久的程序,尤其是服务器进程,如果不及时释放掉不再需要的内存,就会导致内存堆中的占用持续走高,最终可能导致程序崩溃. 不再需要使用的内存,却一直占用着空间,得不 ...
- 【JS档案揭秘】第四集 关于this的讨论到此为止
网上关于this的指向问题的博客文章很多,但大多数都是复制粘贴,也不能用简洁的语言讲清楚,而是不停地写一些示例,看得人云里雾里. 这一集,我只给出结论,以及判定的通用方法,至于是否确实如我所讲,大家可 ...
- 【JS档案揭秘】第三集 深入最底层探秘原型链
关于这部分我看过大量的文章,数不胜数,包括阮一峰的继承三部曲,还有各种慕课的视频教程,网上无数继承方法的对比.也对很多概念存在长期错误的理解.今天做一个正确的总结,用来给原型链和继承这块知识画上句号, ...
- js 在浏览器中的event loop事件队列
目录 前言 认识一个栈两个队列 执行过程 异步任务怎么分配 简单例子 难一点的例子 前言 以下内容是js在浏览器中的事件队列执行,与在nodejs中有所区别,请注意. 都说js是单线程的,不过它本身其 ...
- Js 运行机制和Event Loop
一.为什么JavaScript是单线程? JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事.那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊. Java ...
随机推荐
- 剑指offer第二版-6.从尾到头打印链表
描述:输入一个链表的头节点,从尾到头打印每个节点的值. 思路:从尾到头打印,即为“先进后出”,则可以使用栈来处理:考虑递归的本质也是一个栈结构,可递归输出. 考点:对链表.栈.递归的理解. packa ...
- CDQZ集训DAY8 日记
又一次翻车…… 先提一句昨晚的事.昨天晚上身后一帮成都七中的人用十分戏谑的语气交出了达哥的名字,看着NOI2017的获奖名单,如果他们真的是在嘲笑的话,真的挺想上去干他们一顿的…… 上午考试第一题一脸 ...
- 1.Actor编写-ESGrain与ESRepGrain
ESGrain 生命周期 Ray中ESGrain继承自Grain扩展了Grain的生命周期.Grain的生命周期参见文档附录:1-Grain生命周期-译注.md ESGrain重写了Grain的OnA ...
- 教你发布vue+.netCore项目到服务器
最近一直在做项目,发布部署的事情都是同事或者老大做的,无奈什么事都要自己尝试经历后才能记住,所以发布的事情轮到我了,由于是第一次发布部署项目到一个新的服务器环境,难免会遇到各种各样的问题,总结下来,希 ...
- ubuntu18.04安装nvidia驱动总结经验
本人电脑是 DELL Inspiron 3670, 系统装的是ubuntu18.04, 显卡使用的是GeForce GTX 1050 Ti, 在安装nividia显卡的时候花费两天时间,感受颇深,顾总 ...
- python3.5学习笔记(说明)
本内容是自己在学习python过程中总结的知识点,只用于学习和交流,请勿用作商业用途,部分内容来自网络,如有侵权,联系删除.
- [leetcode] 62 Unique Paths (Medium)
原题链接 字母题 : unique paths Ⅱ 思路: dp[i][j]保存走到第i,j格共有几种走法. 因为只能走→或者↓,所以边界条件dp[0][j]+=dp[0][j-1] 同时容易得出递推 ...
- python的socket模块
sk.bind(address) s.bind(address) 将套接字绑定到地址.address地址的格式取决于地址族.在AF_INET下,以元组(host,port)的形式表示地址. sk.li ...
- python查漏补缺 --- 基础概念及控制结构
python 是一种面向对象的解释型计算机程序设计语言,在运行时由解释器处理,在执行程序之前不需要编译程序.Python就是一句话,写得快,跑得慢. 下面的内容是平时工作中容易忽略掉的小细节,希望借 ...
- 高级查询MYsql(二) 练习
一.单词部分 ①exist存在②temp临时的③district区域 ④content内容⑤temporary暂时的 二.预习部分 1.表连接都可以用子查询替换吗 是的 2.检测某列是否存在某个范围可 ...