有用的内置Node.js APIs( 三 )


node filecompress.js ./test/example.html ./test/output.htmlEvents当发生一些事情时,你经常需要执行多个函数 。比如说,一个用户注册你的app,因此代码必须添加新用户的详情到数据库中 , 开启一个新登录会话,并发送一个欢迎邮件 。
// example pseudo codeasync function userRegister(name, email, password) {try {await dbAddUser(name, email, password);await new UserSession(email);await emailRegister(name, email);}catch (e) {// handle error}}这一系列的函数调用与用户注册紧密相连 。进一步的活动会引起进一步的函数调用 。比如说:
// updated pseudo codetry {await dbAddUser(name, email, password);await new UserSession(email);await emailRegister(name, email);await crmRegister(name, email); // register on customer systemawait emailSales(name, email);// alert sales team}你可以在这个单一的、不断增长的代码块中管理几十个调用 。
Events API提供了一种使用发布订阅模式构造代码的替代方式 。userRegister()函数可以在用户的数据库记录被创建后触发一个事件--也许名为newuser
任意数量的事件处理函数都可以订阅和响应newuser事件;这不需要改变userRegister()函数 。每个处理器都是独立运行的 , 所以它们可以按任意顺序执行 。
客户端JavaScript中的事件事件和处理函数经常在客户端JavaScript中使用 。比如说,当用户点击一个元素时运行函数:
// client-side JS click handlerdocument.getElementById('myelement').addEventListener('click', e => {// output information about the eventconsole.dir(e);});在大多数情况下,你要为用户或浏览器事件附加处理器,尽管你可以提出你自己的自定义事件 。Node.js的事件处理在概念上是相似的 , 但API是不同的 。
发出事件的对象必须是Node.js EventEmitter类的实例 。这些对象有一个emit()方法来引发新的事件 , 还有一个on()方法来附加处理器 。
事件示例项目提供了一个类 , 该类可以在预定的时间间隔内触发一个tick事件 。./lib/ticker.js模块导出一个default class,并extends EventEmitter
// emits a 'tick' event every intervalimport EventEmitter from 'events';import { setInterval, clearInterval } from 'timers';export default class extends EventEmitter {constructor必须调用父构造函数 。然后传递delay参数到start()方法:
constructor(delay) {super();this.start(delay);}start()方法检查delay是否有效,如有必要会重置当前的计时器,并设置新的delay属性:
start(delay) {if (!delay || delay == this.delay) return;if (this.interval) {clearInterval(this.interval);}this.delay = delay;然后它启动一个新的间隔计时器,运行事件名称为"tick"emit()方法 。该事件的订阅者会收到一个包含延迟值和Node.js应用程序启动后秒数的对象:
// start timerthis.interval = setInterval(() => {// raise eventthis.emit('tick', {delay:this.delay,time:performance.now()});}, this.delay);}}event.js入口脚本导入了该模块,并设置了一秒钟的delay时段(1000毫秒) 。
// create a tickerimport Ticker from './lib/ticker.js';// trigger a new event every secondconst ticker = new Ticker(1000);它附加了每次tick事件发生时触发的处理函数:
// add handlerticker.on('tick', e => {console.log('handler 1 tick!', e);});// add handlerticker.on('tick', e => {console.log('handler 2 tick!', e);});第三个处理器仅使用once()方法对第一个tick事件进行触发:
// add handlerticker.once('tick', e => {console.log('handler 3 tick!', e);});最后,输出当前监听器的数量:
// show number of listenersconsole.log(`listeners: ${ // show number of listenersconsole.log(`listeners: ${ ticker.listenerCount('tick') }`);使用node event.js运行代码 。
输出显示处理器3触发了一次,而处理器1和2在每个tick上运行,直到应用程序被终止 。
Streams上面的文件系统示例代码在输出最小化的结果之前将整个文件读入内存 。如果文件大于可用的RAM怎么办?Node.js应用程序将以"内存不足(out of memory)"错误失败 。
解决方案是流 。这将在更小、更容易管理的块中处理传入的数据 。流可以做到: