目标
- 理解JS 单线程、 Node.js EventLoop
- 理解Node.js事件模块
第一部分 前提 Nodejs EventLoop
1 【堆】【栈】【队列】
任何一种语言的运行环境都少不了*堆(heap)栈(Stack)队列 (queue) * JS也不例外。
- JS的
临时变量以及调用时的形参
等等数据都是存储在栈
中; 堆
则是存储实际的对象
;- 对象的
引用变量名(指针)
也是在栈
;
而队列则是JS在实时运行环境中创建的消息队列或者事件队列。
JS是单线程,所以队列的实现让JS的异步处理有了可能性。
2 单线程、任务队列
尽信书不如无书,就喜欢这种有理有据的
摘录自【朴灵评注】JavaScript 运行机制详解:再谈Event Loop
为了避免复杂性,JS从一诞生,同一个时间只能做一件事。JavaScript就是单线程
,这已经成了这门语言的核心特征,将来也不会改变。
为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程
,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。
异步执行的运行机制
(1)所有任务都在主线程上执行,形成一个执行栈(execution context stack)。 |
上面这段初步地在说event loop。但是异步跟event loop其实没有关系。准确的讲,【event loop是实现异步的一种机制】
【上面提到的一系列的手段其实就是实现异步的方法,其中就包括event loop。以及轮询、事件等。】 |
【JavaScript运行环境的运行机制,不是JavaScript的运行机制。】
3 事件循环
首先我们看一下nodejs本质结构图
Node.js 通过 libuv 来处理与操作系统的交互,并且因此具备了【异步、非阻塞、事件驱动】的能力。Node.js 实际上是 Javascript 执行线程的单线程,真正的I/O 操作,底层 API 调用都是通过多线程执行
的。
本质也就是:任务接收是单线程,任务执行是多线程。
那么也就是主要依靠libuv
,那么本文主要介绍Nodejs事件模块,当然离不开原理
为何是这样?
为何这么吊?
为何又出现那么多回调函数?
带着一些列问题搞明白了理论,至于代码,那也调用哪些大神写的API吧!
膜拜大神三秒钟
技术(艺术)源自生活、高于生活。对吧。
只要开始启动,那么这个姑娘就开始嗨起来了,其实我们事件循环也是这样的!从启动开始,就一直不停止的监听。
【论英文的重要性】
一图胜千言,但我还是就下图做个简单的梳理吧。我可不想被同为学渣的老铁们骂哈。
我们程序猿其实工作还是仅限于代码调用编写阶段,主要的核心在于理解内部原理,然后根据需求去编写(复制)代码。
讲个故事吧
JS单身狗(单线程)无异议,但它也是个贪心的黑心老板,在外边一直接活一直接活,根本无视 |
Nodejs中是怎么个情况,请看下图
好了,结束了,接下来就是代码啦。
第二部分 Events模块概述
1 Events模块
Events模块是Node对“发布/订阅”模式(publish/subscribe)的实现。一个对象通过这个模块,向另一个对象传递消息。
Node中的Event模块仅仅提供了一个对象: *EventEmitter, EventEmitter 的核心*就是事件触发与事件监听器功能的封装。
获取EventEmitter对象
//引用模块events, 点语法获取到EventEmitter |
2 EventEmitter 实例对象的方法
2.1 emitter.on(eventName, listener), 监听事件,如果触发就调用回调函数
1. eventName <String> | <Symbol>: 事件名称, 后边可以跟上函数; |
2.2 emitter.emit(eventName[, …args]), 根据eventName发送通知, 触发事件, 第一个参数为事件名称, 其余的参数会依次传入回调函数
以上两个方法的示例代码
var EventEmitter = require('events').EventEmitter; |
打印结果为:
$ node 2on.js |
2.3 emitter.once(eventName, listener), 类似on方法, 但回调函数只是执行一次
var EventEmitter = require('events').EventEmitter; |
执行的结果为:
$ node 3once.js |
虽然触发多次oncefun, 但依然打印一次;与下边形成对比;,
2.4 emitter.addListener(eventName, listener)类似于emitter.on(eventName, listener)
2.5 emitter.removeListener(eventName, listener), 移除监听
详细见实例代码:
var EventEmitter = require('events').EventEmitter; |
打印结果
$ node 5removeListener.js |
######第三部分 更多API详见
语法名称觉得挺好的, 见名知意. 更多的语法就看Node官网吧 -__-
Event: 'newListener' |
Related Issues not found
Please contact @simuty to initialize the comment