| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> JavaScript知识库 -> Node.js 事件驱动 -> 正文阅读 |
|
[JavaScript知识库]Node.js 事件驱动 |
Node.js 最主要的两个亮点就是异步I/O 和 事件驱动。那么啥是事件驱动呢? 目录 addEventListner和removeEventListener Node.js的events模块下的EventEmitter 浏览器的事件驱动在没有学习Node.js之前,我们就已经知道了事件驱动这个名词,因为浏览器端就实现了事件驱动。 浏览器的事件驱动机制指的就是DOM元素的事件绑定,DOM元素的事件绑定分为了HTML级,DOM0级,DOM2级,其中DOM2级是最新实现 addEventListner和removeEventListenerDOM2级事件绑定,有两个关键的方法addEventListner(用于注册事件处理程序)和removeEventListener(用于解绑事件处理程序)
事件绑定三要素在浏览器的事件绑定中存在三个要素:事件源,事件类型,事件处理程序 比如上面DOM2级示例中,btn元素就是事件源,click是事件类型,callback就是事件处理程序。 而所谓事件驱动机制,在浏览器中就可以解释为: 当 btn元素 发生click事件时,才执行callback回调函数。 浏览器的事件绑定中的回调函数是同步执行的但是需要注意的是callback是同步执行的,而不是异步执行的:
那么 浏览器端的DOM元素事件绑定是如何实现 回调函数的延迟同步执行,而不是异步执行的呢? 事件驱动与发布订阅模式在浏览器中,存在一个专门用于处理事件的线程,该线程内部会为每一个DOM元素都创建一个用于缓存事件处理程序的队列,当DOM元素使用addEventListener在某事件类型上注册回调函数时,该回调函数就会被缓存到事件处理线程内部的队列中。 当该DOM元素的该事件类型触发后,事件处理线程就会按照队列出队的方式依次取出回调函数出来同步执行。 而浏览器端事件驱动在实现上,完全符合发布订阅模式。 发布订阅模式所谓发布订阅模式,一般由三部分组成:订阅者,发布者,调度中心 订阅者将订阅信息 发送到 调度中心,由调度中心缓存 发布者将发布消息 发送到 调度中心,由调度中心发布(即告知相应的订阅者) 具体实现上: 程序员使用addEventListner订阅btn元素的click事件,并将回调函数发送到调度中心, 调度中心 监听 btn元素的click事件,当事件触发时,调度中心就会直接触发回调函数。 可以发现这里调度中心 指的就是 浏览器事件处理线程,及其内部的事件队列。 浏览器端事件驱动模拟实现
以上是对调度中心的模拟实现 Node.js 的事件驱动Node.js 的事件驱动在原理上,和浏览器的事件驱动本质相同,都是基于发布订阅模式。 差别在于,浏览器的事件驱动大部分是基于UI事件,如鼠标点击事件,键盘敲击事件, 而 Node.js 作为后端环境,不存在UI交互,所以 Node.js 的事件在理解上会更加抽象,但是我们依旧可以从事件源,事件类型,事件处理程序三个要素去理解。 在浏览器事件驱动中,事件源是DOM元素。 Node.js的events模块下的EventEmitter在Node.js事件驱动中,事件源是可以是任意一个继承自Node.js的内置模块events的EventEmitter的类的实例。 当某个类继承EventEmitter后,其实例的私有属性如下 实例上会具有_events属性,该属性指向一个空对象,用于缓存事件类型和事件处理程序,事件类型作为空对象的属性名,事件处理程序作为空对象的属性值,当一个事件类型下有多个事件处理程序时,会被包装进一个数组中,并将该数组作为新的属性值 ? ? ? ? ? ? ? ? ? ? ? _eventsCount,该属性用于记录注册事件类型的个数 ? ? ? ? ? ? ? ? ? ? ? _maxListeners,该属性用于记录每个事件最多能注册多少个事件处理程序 当某个类继承EventEmitter后,其实例就拥有了EventEmitter原型上的方法 ?其中on,once用于注册事件处理程序,emit用于触发事件处理程序,off用于取消事件处理程序 关于on的注意事项on可以为某个实例的某个事件类型注册多个事件处理程序,并且emit触发该事件类型时,会按照先进先出的原则依次触发注册的事件处理程序 on注册的事件处理程序,即回调函数的this就是实例本身,注意如果回调函数是箭头函数,则没有this,箭头函数中使用的this指向箭头函数定义时所在作用域的this。
这里关于node模块作用域下的this,模块中函数作用域下的this指向简单说明下: node模块作用域下的this指向module.exports初始时指向的空对象,模块中函数作用域下的this指向函数的调用者,即四种场景(默认绑定【无调用者,默认是全局对象global】,隐式绑定【有调用者,this隐式指向调用者】,new绑定【this指向new创建的对象】,硬绑定【this指向call,apply,bind指定的对象】) ?关于once使用注意事项once和on,在多个事件处理程序绑定,以及事件处理程序(回调函数)的this指向上的设计相同。 即once也可以为某个实例的某个事件类型绑定多个事件处理程序,并且emit触发该实例的该事件类型时,多个事件处理程序会先进先出依次执行。 once指定的事件处理程序(回调函数)的this也是指向实例本身,若为箭头函数,则this指向箭头函数定义时所在作用域的this。 once和on的区别,once注册的事件处理程序只能被emit触发一次,相当于执行一次后,once注册的事件处理程序就会出队列。而on注册的事件处理程序会被缓存,可以被多次执行。
观察MyModule实例的_events是由属性,发现“事件1”的事件处理程序在被emit触发后已经全部出队了。? 关于emit使用注意事项emit用于触发注册在EventEmitter实例上的某事件类型下的所有回调函数,并且会依次执行。 emit可以传参给事件回调函数。 关于off的使用注意事项off用于解除实例下指定事件类型的指定事件回调函数,这里要求绑定的事件回调函数是具名函数。 注册的事件处理程序是同步执行的我们需要注意的是,由于Node.js的事件驱动也是基于发布订阅模式的,所以Node.js的事件回调函数也是同步执行的。 ?原理是,Node.js中,当我们为某个EventEmitter实例注册事件回调函数时,该事件回调函数其实被缓存在了该实例的_events属性中,当事件触发时,再从该实例的_events属性中取出对应事件类型的回调函数执行。 模拟实现Node.js的事件驱动EventEmitter
EventEmitter实现难点主要在于once,由于once是一次性注册,即注册的事件处理程序在调用后就会被取消注册,即需要在事件处理程序调用中执行off操作,所以只能进行函数包装,最终将包装函数注册。 但是将once注册的事件处理程序包装后,off将无法取消注册对应的事件处理程序,原因是once时机注册的是包装函数,而不是原函数,而off只能获取到原函数,所以需要在包装原函数时,建立原函数和包装函数的关系,即callback.link = wrap EventEmitter内置事件类型之前我们使用的事件都是自定义的事件类型,如“事件1”,在EventEmitter中,事件类型只是一个简单的字符串,而EventEmitter为我们准备了两个通用的内置事件类型 newListener:当为EventEmitter实例注册新的事件处理程序时,newListener事件会被触发 removeListener:当为EventEmitter实例移除某事件处理程序时,removeListener事件会被触发
可以发现newListener和removeListener事件的回调函数都有两个参数:type和callback 即事件类型和事件处理程序 。 这些内置事类型和自定义事件类型的区别在于:自定义事件类型需要手动emit,而newListener和removeListener可以实现不通过emit触发事件,原因是Node.js系统内部帮我们自动emit了,优点类似于浏览器端UI事件被UI页面动作被触发后,浏览器的事件处理线程自动emit事件处理程序。 |
|
JavaScript知识库 最新文章 |
ES6的相关知识点 |
react 函数式组件 & react其他一些总结 |
Vue基础超详细 |
前端JS也可以连点成线(Vue中运用 AntVG6) |
Vue事件处理的基本使用 |
Vue后台项目的记录 (一) |
前后端分离vue跨域,devServer配置proxy代理 |
TypeScript |
初识vuex |
vue项目安装包指令收集 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 13:01:47- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |