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 如何通过单线程来实现高并发 ...
随机推荐
- python 报错 wxPyDeprecationWarning: Using deprecated class PySimpleApp.
如题:python 报错 提示为 : wxPyDeprecationWarning: Using deprecated class PySimpleApp. 解决:将 wx.PySimpleApp() ...
- Nuget管理自己的项目库
Nuget是什么 Nuget 是一种 Visual Studio 扩展工具,它能够简化在 Visual Studio 项目中添加.更新和删除库(部署为程序包)的操作.(官方地址)相信大家对这个应该还是 ...
- 058 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 05 案例:求数组元素的最大值
058 01 Android 零基础入门 01 Java基础语法 06 Java一维数组 05 案例:求数组元素的最大值 本文知识点:求数组元素的最大值 案例:求数组元素的最大值 程序代码及其执行过程 ...
- Python3基础——字符串类型
Text Sequence Type - str(immutable) class str(object='') class str(object=b'', encoding='utf-8', err ...
- 【题解】小M的作物
题目戳我 \(\text{Solution:}\) 这题要求最大收获,可以转化为所有可能的收益减去最小割. 单个点很好连边 \((S\to pos\to T),\) 问题在于如何处理组合的点. 观察到 ...
- java高级项目 jdbc与数据库连接数据库
//图书管类 public class Book { private Integer id; private String b_name; private double b_price; privat ...
- 基于Intel x86 Android的RAD游戏开发
zip文件还包含编译的"MonkeyGame-debug".可以在模拟器中运行的二进制文件.在"game.build"文件夹中有一个HTML5 build.在C ...
- visio调整画布大小的简便方法
按住Ctrl,然后鼠标在边缘拉拽即可.
- English 介词
English 介词 Create Time : 2019-06-27 表示时间的介词称为时间介词.表示时间的介词有:at, on, in, before, after等. 一.at, on和in ① ...
- MeteoInfoLab脚本示例:inpolygon
inpollygon函数是用来判断带坐标(x/y)的数据是否在某个或者一组多边形(Polygon)中,返回的结果中如果做多边形内则值为1,否则值为-1.下面一个例子演示了利用一个shape文件和inp ...