js的事件处理程序底层原理(关于js的事件循环机制剖析)
js的事件处理程序底层原理
关于js的事件循环机制剖析前言
众所周知, JavaScript是单线程这一核心,可是浏览器又能很好的处理异步请求,那么到底是为什么呢?其中的原理与事件循环机制大有关系。
在探索事件循环之前,我们得先了解浏览器执行线程~~
浏览器的渲染进程是多线程的,浏览器每一个tab标签都代表一个独立的进程,其中浏览器内核属于浏览器多进程中的一种,主要负责页面渲染,脚本执行,事件处理等。其包含的线程有以下几种
GUI 渲染线程:负责渲染页面,解析 HTML,CSS 构成 DOM 树;
JS 引擎线程:解释执行代码、用户输入和网络请求;
事件处理线程:click、mouse等交互事件发生后将事件函数放入队列;
定时器触发线程:等时间结束后执行函数推入任务队列中;
http网络请求线程:处理用户的get、post请求,返回结果推入任务队列中。
了解了浏览器渲染流程,还要了解JS的运行机制。JS的运行机制就是事件循环
执行栈
JS运行的环境称之为宿主环境。
执行栈:call stack,一个数据结构,用于存放各种函数的执行环境,每一个函数执行之前,它的相关信息会加入到执行栈。函数调用之前,创建执行环境,然后加入到执行栈;函数调用之后,销毁执行环境。
事件循环
js中所有的任务可以分为同步任务和异步任务,同步任务是立即执行的任务,同步任务一般会直接进入到主线程中执行;而异步任务,就是异步执行的任务,比如ajax网络请求,setTimeout 定时函数等都属于异步任务,异步任务会通过任务队列(先进先出)的机制来进行协调。同步和异步任务分别进入不同的执行环境,同步的进入主线程,即主执行栈,异步的进入任务队列。主线程内的任务执行完毕为空,会去任务队列读取对应的任务,推入主线程执行。 这种不断重复就是我们说的 Event Loop (事件循环)。具体流程如下图。
在事件循环中,每进行一次循环操作称为tick,每一次 tick 的任务键的步骤可以总结如下:1.执行一个宏任务(栈中没有就从事件队列中获取);2.执行过程中如果遇到微任务,就将它添加到微任务的任务队列中;3.宏任务执行完毕后,立即执行当前微任务队列中的所有微任务(依次执行);4.当前宏任务执行完毕,开始检查渲染,然后GUI线程接管渲染;5.渲染完毕后,JS线程继续接管,开始下一个宏任务(从事件队列中获取)
宏任务主要包含:script( 整体代码)、setTimeout、setInterval、I/O、UI 交互事件、setImmediate(Node.js 环境)
微任务主要包含:Promise、MutaionObserver、process.nextTick(Node.js 环境)
事件循环例子
console.log('script start'); //整体 script 作为第一个宏任务进入主线程,遇到 console.log,输出 script start setTimeout(function() { console.log('setTimeout'); }, 0); //遇到 setTimeout,其回调函数被分发到宏任务 Event Queue 中 Promise.resolve().then(function() { console.log('promise1'); }).then(function() { console.log('promise2'); }); //遇到 Promise,其 then函数被分到到微任务 Event Queue 中,记为 then1,之后又遇到了 then 函数,将其分到微任务 Event Queue 中,记为 then2 console.log('script end'); //遇到 console.log,输出 script end
如此,Event Queue(事件队列)中存在三个任务:宏任务:setTimeout 微任务:then1、then2。执行微任务首先then1,输出 promise1, 然后执行 then2,输出 promise2,这样就清空了所有微任务
执行 setTimeout 任务,输出 setTimeout 至此,输出的顺序是:script start, script end, promise1, promise2, setTimeout
总结:
JavaScript 是一门单线程语言,异步操作都是放到事件循环队列里面,等待主执行栈来执行的,并没有专门的异步执行线程。
到此这篇关于js的事件循环机制的文章就介绍到这了,更多相关js事件循环内容请搜索开心学习网以前的文章或继续浏览下面的相关文章希望大家以后多多支持开心学习网!
- python获取json结果保存文本(Python JSON格式数据的提取和保存的实现)
- extjs card卡片式布局
- js怎么转拼音(js实现中文转拼音的完整步骤记录)
- js如何生成随机数
- html5长图拖动(html5 拖拽及用 js 实现拖拽功能的示例代码)
- html5音频处理(recorder.js 基于Html5录音功能的实现)
- laravel-admin代码执行流程(解决laravel-admin 自己新建页面里 js 需要刷新一次的问题)
- js原型链的理解(浅谈JS的原型和原型链)
- dedecms中的有些功能如何修改(织梦DEDECMS中用JS方式调用评论总数的技巧)
- js 全局变量与局部变量
- Extjs中文乱码
- vue怎么定义router的动态路由(vue.js Router中嵌套路由的实用示例)
- js中事件的三个阶段(JavaScript中事件冒泡机制示例详析)
- 通过js获取Url的参数值
- react实现js控制样式(React + Threejs + Swiper 实现全景图效果的完整代码)
- jscanvas背景色(JavaScript canvas实现代码雨效果)
- 魔兽争霸3自定义战役少年杰雷 2(魔兽争霸3自定义战役少年杰雷)
- 今日菜价 芥兰涨幅最高 1.33 ,花菜降幅最高 3.10(今日菜价芥兰涨幅最高)
- 今日菜价 椰菜涨幅最高 3.25 ,水空心菜降幅最高 2.58(今日菜价椰菜涨幅最高)
- 今日菜价 红三鱼涨幅最高 4.41 ,黄鳝降幅最高 5.06(红三鱼涨幅最高)
- 今日菜价 西生菜涨幅最高 6.19 ,生菜降幅最高 5.38(西生菜涨幅最高)
- 今日菜价 青豆角涨幅最高 0.70 ,菜心降幅最高 5.55(青豆角涨幅最高)
热门推荐
- docker端口映射详解(docker 启用多个端口映射命令的操作)
- dockernginx怎么设置容器(docker nginx + https 子域名配置详细教程)
- css继承属性有哪些(CSS特殊性、继承与层叠)
- mysql查询时间格式化(MySQL时间格式化)
- sql语言怎么删除某列(SQL删除多列语句的写法)
- 阿里云注册域名ddns怎么写(如何通过阿里云实现动态域名解析DDNS的方法)
- php中类的属性含义(php类中static与self的使用区别浅析)
- 正则表达式在python的中的应用(Python中正则表达式的用法总结)
- SQL Server中查看未释放的游标
- nginx网站集群(Nginx实现高可用集群构建Keepalived+Haproxy+Nginx)