js——事件循环
JS—事件循环
js运行的环境称之为宿主环境。
执行栈 :call stack ,一个数据结构,用于存放各种函数的执行环境,每一个函数执行之前他的相关信息会加入到执行栈中,函数调用之前,创建执行环境,然后加入到执行栈中;函数调用之后,销毁执行环境
function a (){
console.log("a")
b()
}
function b(){
console.log("b")
c()
}
function c(){
console.log("c")
}
console.log("global")
a()
执行顺序: global a b c
答案显而易见,但是为什么会这样呢?
整个js运行了之后 就只有一个执行栈,首先整个js定义了三个函数,js代码在运行的时候都会先初始化一个全局上下文GO,然后把GO放入在call stack 中,接着console.log()函数执行,创建一个log的上下文放入call stack,输入“global”之后log的上下文就会销毁,然后a()函数执行,创建一个a的上下文放入call stack,输出"a",b()执行,这时a函数还没有结束,因为a函数里面还需要执行b函数,所以a的上下文还留在call stack中,b() 函数执行,创建一个b的执行上下文放入call stack 中,b函数出入"b",c(),这时b函数也还没有结束,还需要执行c()函数,所以b的上下文也还在call stack中没有销毁,c()函数执行,创建一个c的上下文放入到call stack中,c函数输出"c"后,c函数结束,call stack里面的c的上下文销毁,c函数执行完,b函数也就执行完了所以,接着,b的上下文也接着销毁,b函数执行完后a函数也就代表着执行完,所以a的上下文也接着被销毁,最后这整个js代码运行完后call stack里面最先初始化创建的全局上下文就销毁。
再来一个例子巩固一下上面的原理:求斐波拉契数列 第一个和第二个数固定为1,之后任意一个数都是前两位数之和
function getFeibo(n){
if(n ===1 || n===2 ){
return 1;
}
return getFeibo(n-1) + getFeibo(n-2)
}
console.log(getFeibo(3))
首先初始化一个全局上下文放入call stack 中 log()执行 创建一个log的执行上下文放入call stack 中 这时getFeibo(3)执行,创建一个n=3的getFeibo的执行上下文,n=3没有进入if语句,执行getFeibo(3-1)函数,创建一个n=2 的getFeibo的执行上下文,进入if语句 返回1,n=2的getFeibo的执行上下文销毁,return的前部分结束,执行 getFeibo(3-2)函数,创建一个 n=1 的getFeibo的执行上下文, 进入if语句,返回1,n=1的getFeibo的执行上下文销毁,return的后部分结束 n=3的getFeibo函数运行结束返回2 ,n=3的getFeibo的执行上下文销毁,最后初始化的那个全局上下文也销毁这时call stack清空。
js引擎永远执行的都是执行栈的最顶部
异步函数:某些函数不会立即执行,需要等到某个时机到达后才会执行,这样的函数就被称之为异步函数,比如时间处理函数。异步函数的执行时机,会被宿主环境控制。
浏览器宿主环境中包含有5个线程:
- JS引擎:负责执行执行栈的最顶部代码
- GUI线程:负责渲染页面
- 事件监听线程:负责监听各种事件
- 计时线程:负责计时(setTimeout、setInterval)
- 网络线程:负责网络通信 如 ajax
当上面的线程发生了某些事情,如果该线程发现,这件事情有处理程序,他就会将该处理程序放入到一个叫做事件队列的的内存里,当JS引擎发现,执行栈call stack 中里面已经没有任何内容后,call stack就会把事件队列中的第一个函数加入到执行栈中去执行
例如:
function a(){
console.log("a")
setTimeout(()=>{
b()
},0)
c()
}
function b(){
console.log("b")
}
function c(){
console.log("c")
}
console.log("global")
a()
输出顺序:global a c b
首先初始化一个全局执行上下午放入call stack中 log()函数执行,创建一个log的执行上下文,输出global,log的执行上下文销毁,a函数执行,创建一个a的执行上下文,log执行创建一个log的执行上下文,输出a,log的执行上下文销毁,setTimeout 开启一个定时器告诉宿主环境0秒后执行b函数,注意这时b函数还没有执行,就紧接着执行c函数
创建一个c的执行上下文,log执行创建一个log的执行上下文,输出c,log的执行上下文销毁,这时a函数里面的代码执行完 a的执行上下文被销毁,整个js代码执行完毕,全局上下文也从call stack被销毁,call stack清空。这时有人会问 诶 b函数不是还没有执行吗怎么说整个js代码执行完毕了呢? 是这样的 setTimeout开启了一个定时器,这时已经是计时线程发现了有处理程序,会告诉宿主环境 0 秒后执行b函数,宿主环境知道后就会在0秒过后把 b函数放入到一个叫事件队列的内存中。所以当call stack 里面的内容清空后(即当最开始初始化的全局上下文被销毁后)JS引擎会从事件队列中取出处理程序来执行。
JS引擎从事件队列中取出处理程序来执行,以及与宿主环境的配合,称之为事件循环
事件队列在不同的宿主环境中有所差异,大部分宿主环境会将事件队列进行细分。在浏览器中,事件队列被分为两种:
- 宏队列:macroTask,计时器结束的回调、事件回调、http回调等等绝大部分异步函数是进入宏队列
- 微队列:MutationObserver,Promise产生的回调进入微队列
当执行栈清空是,JS引擎首先会将微任务中的所有任务一次执行结束,如果没有微任务,则执行宏任务。
js——事件循环的更多相关文章
- Node.js 事件循环(Event Loop)介绍
Node.js 事件循环(Event Loop)介绍 JavaScript是一种单线程运行但又绝不会阻塞的语言,其实现非阻塞的关键是“事件循环”和“回调机制”.Node.js在JavaScript的基 ...
- Node.js事件循环
Node JS是单线程应用程序,但它通过事件和回调概念,支持并发. 由于Node JS每一个API是异步的,作为一个单独的线程,它使用异步函数调用,以保持并发性.Node JS使用观察者模式.Node ...
- js事件循环机制辨析
对于新接触js语言的人来说,最令人困惑的大概就是事件循环机制了.最开始这也困惑了我好久,花了我几个月时间通过书本,打代码,查阅资料不停地渐进地理解他.接下来我想要和大家分享一下,虽然可能有些许错误的 ...
- 6、Node.js 事件循环
#########################################################################################Node.js 事件循 ...
- Node.js 事件循环
Node.js 是单进程单线程应用程序,但是通过事件和回调支持并发,所以性能非常高. Node.js 的每一个 API 都是异步的,并作为一个独立线程运行,使用异步函数调用,并处理并发. Node.j ...
- Node.js 学习(五)Node.js 事件循环
Node.js 是单进程单线程应用程序,但是通过事件和回调支持并发,所以性能非常高. Node.js 的每一个 API 都是异步的,并作为一个独立线程运行,使用异步函数调用,并处理并发. Node.j ...
- js事件循环
之前有看过一些事件循环的博客,不过一阵子没看就发现自己忘光了,所以决定来自己写一个博客总结下! 首先,我们来解释下事件循环是个什么东西: 就我们所知,浏览器的js是单线程的,也就是说,在同一时刻,最多 ...
- [译] 所有你需要知道的关于完全理解 Node.js 事件循环及其度量
原文地址:All you need to know to really understand the Node.js Event Loop and its Metrics 原文作者:Daniel Kh ...
- Node.js 事件循环机制
Node.js 采用事件驱动和异步 I/O 的方式,实现了一个单线程.高并发的 JavaScript 运行时环境,而单线程就意味着同一时间只能做一件事,那么 Node.js 如何通过单线程来实现高并发 ...
随机推荐
- ThreeJS系列1_CinematicCameraJS插件详解
ThreeJS系列1_CinematicCameraJS插件详解 接着上篇 ThreeJS系列1_CinematicCameraJS插件介绍 看属性的来龙去脉 看方法作用 通过调整属性查看效果 总结 ...
- JAVA学习线路:day01面向对象(继承、抽象类)
所有的文档和源代码都开源在GitHub: https://github.com/kun213/DailyCode上了.希望我们可以一起加油,一起学习,一起交流. day01面向对象[继承.抽象类] 今 ...
- jquery购物车全选,取消全选,计算总金额
这是html代码 <div class="gwcxqbj"> <div class="gwcxd center"> <div cl ...
- C#实例(经典):四路光电开关&激光雷达数据采集和波形图绘制
前言:本文全部纯手工打造,如有疏漏之处,还请谅解! 如果需要查看更多文章,请微信搜索公众号 csharp编程大全,需要进C#交流群群请加微信z438679770,备注进群, 我邀请你进群! ! ! 这 ...
- kubernetes-介绍与特性
1. kubernetes概述 1) kubernetes是什么 2) kubernetes能做什么 3) kubernetes特性 4) kubernetes集群架构与组件 5) kubernete ...
- 2017-01-26--编译Linux内核2.6.30版本报错解决
错误一: LD .tmp_vmlinux1 init/built-in.o: In function `run_init_process': /home/ox/tq2440/opt/EmbedSky/ ...
- pytest文档48-切换 base_url 测试环境(pytest-base-url)
前言 当我们自动化代码写完成之后,期望能在不同的环境测试,这时候应该把 base_url 单独拿出来,能通过配置文件和支持命令行参数执行. pytest-base-url 是 pytest 里面提供的 ...
- 【并查集】BZOJ 1854 连续攻击游戏
题目内容 洛谷链接 lxhgww最近迷上了一款游戏,在游戏里,他拥有很多的装备,每种装备都有2个属性,这些属性的值用[1,10000]之间的数表示.当他使用某种装备时,他只能使用该装备的某一个属性.并 ...
- MySQL数据库基础-2范式
数据库结构设计 范式 设计数据库的规范 第12345范式,凡是之间有依赖关系. 关系模型的发明者埃德加·科德最早提出这一概念,并于1970 年代初定义了第一范式.第二范式和第三范式的概念 设计关系数据 ...
- Storage API简介和存储限制与逐出策略
目录 简介 常用的客户端存储方式 data storage的类型 逐出策略 Storage API estimate persist persisted 综合使用 总结 简介 对于现代浏览器来说,为了 ...