本文概述
- 使用ECMAScript 5的示例
- 使用ECMAScript 6的示例
所有发出事件的对象都是EventEmitter类的实例, 这些对象公开一个eventEmitter.on()函数, 该函数允许将一个或多个函数附加到该对象发出的命名事件。通常, 事件名称是驼峰式的字符串, 但是可以使用任何有效的JavaScript属性键。
在本文中, 你将学习如何将它们用于ECMAScript 5和6。
ES5
如果你使用的是ECMAScript 5, 那么对于Java初学者来说, 事件发射器的用法就不太清楚了:
// yourLibrary.js// Instantiate event emitter and inheritsvar EventEmitter = require('events');
var inherits = require('util').inherits;
// Create the constructor of YourLibrary and add the EventEmitter to the this contextfunction YourLibrary() {EventEmitter.call(this);
}// Use Inheritance to add the properties of the DownloadManager to event emitterinherits(YourLibrary, EventEmitter);
// Export YourLibrary !module.exports = YourLibrary;
在从YourLibrary创建实例期间执行EventEmitter.call(this)时, 会将EventEmitter构造函数声明的属性附加到YourLibrary。然后, 继承函数将原型方法从一个构造函数继承到另一个构造函数(你的构造函数YourLibrary和超级构造函数EventEmitter), 这样, 你的构造函数的原型将设置为从superConstructor创建的新对象。
由于你的库显然不会提供EventEmitter的相同方法, 因此你需要通过在module.exports行之前或之后使用原型将自己的函数添加到YourLibrary中:
//yourLibrary.jsYourLibrary.prototype.testAsyncMethod = function testAsyncMethod(someData) {_this = this;
// Execute the data event in 2 secondssetTimeout(function(){// Emit the data event that sends the same data providen by testAsyncMethod _this.emit("data", someData);
}, 2000);
};
上一个函数将testAsyncMethod添加到你的库中, 该方法将一些数据作为第一个参数, 并将通过data事件再次发送, 该事件是使用EventEmitter类的继承方法发出的。通过这种方式, YourLibrary使用Node.js的事件管理器, 并且可以用来创建有条理且易于阅读的代码:
// otherfile.js// Require YourLibrary filevar YourLibrary = require("./yourLibrary");
// Create an instance of YourLibraryvar libInstance = new YourLibrary();
// Add the "data" event listener to your library and add some callbacklibInstance.on("data", function(data){// Outputs: "Hello World, data test"console.log(data);
});
// Execute the testAsyncMethod of your librarylibInstance.testAsyncMethod("Hello World, data test");
尽管处理异步事件可能会有些棘手, 但最后一切都会变得有意义, 因此, 如果你还不了解它, 请耐心等待并仔细分析示例。
ES6
使用EcmaScript 6, 该任务确实得到了简化, 并且比ES5更容易处理和理解。但是, 它的工作方式相同:通过使用extends关键字, 你的类可以扩展EventEmitter, 从而明显继承其方法, 因此可以使用emit方法触发事件:
const EventEmitter = require('events');
class YourLibrary extends EventEmitter {constructor() {super();
}testAsyncMethod(data) {this.emit('data', data);
}}module.exports = YourLibrary
然后, 可以从另一个文件轻松使用YourLibrary:
const MyLibrary = require('./yourLibrary');
const libInstance = new MyLibrary();
libInstance.on('data', (data) =>
{// Outputs : Received data: "Hello World, data test"console.log(`Received data: "${data}"`);
});
libInstance.testAsyncMethod("Hello World, data test");
如你所见, 这比使用ES6处理相同的代码要容易得多。
使用ECMAScript 5的示例如果你没有在介绍中找到它, 请放心, 我们确信将示例作为现实世界中的库(或类似的东西)来处理将有助于你理解。在此示例中, 假设我们将使用下载管理器库, 该库确实非常简单, 它提供了一种从服务器异步下载文件的方法。使用Node.js的Event Emitters类, 你可以知道文件的下载时间, 并可以了解下载的进度。
该示例并没有真正下载任何内容, 我们只是使用setInterval(用于progress事件)和setTimeout(用于downloadSuccess事件)函数来模拟下载。在工作区的某个文件夹中创建fileDownloader.js, 并在其上添加以下代码:
// fileDownloader.jsvar EventEmitter = require('events');
var inherits = require('util').inherits;
// Create the constructor of DownloadManager and add the EventEmitter to the this contextfunction DownloadManager() {EventEmitter.call(this);
}// Use Inheritance to add the properties of the event emitter to DownloadManagerinherits(DownloadManager, EventEmitter);
// Export the Download Managermodule.exports = DownloadManager;
//// Write your library down here by prototyping !///** * @param URL {String} Url of the imaginary file to download */DownloadManager.prototype.downloadAsync = function downloadAsync(URL) {var _this = this;
var progress = 0;
console.log('Download file "' + URL + '" ...');
// Trigger the progress event every secondvar progressInterval = setInterval(function() {progress += 20;
// Emit progress event with the progress as argument_this.emit('progress' , progress);
}, 1000);
// Trigger the downloadSuccess event in 5.5 seconds and clear the progress intervalsetTimeout(function() {var optionalDataResponse = {filename: "imaginary.txt", filesize: 123123, fileUrl: URL};
// Stop triggering progressclearInterval(progressInterval);
// Use the emit method of the EventEmitter to trigger the downloadSuccess event !_this.emit('downloadSuccess' , optionalDataResponse);
}, 5500);
};
然后可以按以下方式使用下载管理器(在本示例中为index.js文件):
// index.js// Require the download manager libraryvar DownloadManager = require("./fileDownloader");
// Create an instance of the Download Managervar downloader = new DownloadManager();
// Add event listener of the progress of downloaddownloader.on("progress", function (progress){console.log('Download progress: '+ progress +'%');
});
// Do something when the download of the file endsdownloader.on("downloadSuccess", function (response){//{//filename: "imaginary.txt", //filesize: 123123//}console.log(response);
});
// Start downloaddownloader.downloadAsync("file.txt");
并使用节点index.js执行脚本, 你将获得以下输出:
Download file "file.txt" ...Download progress: 20%Download progress: 40%Download progress: 60%Download progress: 80%Download progress: 100%{ filename: 'imaginary.txt', filesize: 123123, fileUrl: 'file.txt' }
使用ECMAScript 6的示例对于ES6中的示例, 我们将使用与ES5中第一个示例相同的想法, 假设我们将使用Download Manager库, 这个库非常简单, 它提供了一种从服务器异步下载文件的方法。使用Node.js的Event Emitters类, 你可以知道文件的下载时间, 并可以了解下载的进度。
该示例并没有真正下载任何内容, 我们只是使用setInterval(用于progress事件)和setTimeout(用于downloadSuccess事件)函数来模拟下载。在工作区的某个文件夹中创建fileDownloader.js, 并在其上添加以下代码:
const EventEmitter = require('events');
class DownloadManager extends EventEmitter {constructor() {super();
}downloadAsync(URL) {let _this = this;
let progress = 0;
console.log(`Download file '${URL}' ...`);
// Trigger the progress event every secondlet progressInterval = setInterval(() =>
{progress += 20;
// Emit progress event with the progress as argument_this.emit('progress', progress);
}, 1000);
// Trigger the downloadSuccess event in 5.5 seconds and clear the progress intervalsetTimeout(() =>
{let optionalDataResponse = {filename: "imaginary.txt", filesize: 123123, fileUrl: URL};
// Stop triggering progressclearInterval(progressInterval);
// Use the emit method of the EventEmitter to trigger the downloadSuccess event !_this.emit('downloadSuccess', optionalDataResponse);
}, 5500);
}}module.exports = DownloadManager
下载管理器可用于其他文件(index.js):
// index.js// Require the download manager libraryconst DownloadManager = require('./fileDownloader');
// Create an instance of the Download Managerconst downloader = new DownloadManager();
// Add event listener of the progress of downloaddownloader.on("progress", (progress) =>
{console.log(`Download progress ${progress}%`);
});
// Do something when the download of the file endsdownloader.on("downloadSuccess", (response) =>
{//{//filename: "imaginary.txt", //filesize: 123123//}console.log(response);
});
// Start downloaddownloader.downloadAsync("file.txt");
使用节点index.js执行脚本, 你将获得以下输出(与ES5中的示例相同):
Download file "file.txt" ...Download progress: 20%Download progress: 40%Download progress: 60%Download progress: 80%Download progress: 100%{ filename: 'imaginary.txt', filesize: 123123, fileUrl: 'file.txt' }
【如何轻松在Node.js中将事件发射器与ES5和ES6结合使用】在使用Node.js的EventEmitter类时, 你可以使用库中此类的所有方法, 因此不要忘记查看Node.js的文档以了解有关事件发射器的更多信息。
编码愉快!
推荐阅读
- 如何在Node.js中递归读取目录
- 如何使用Node.js中的文件系统(fs)模块创建文件
- 如何在Node.js中将文本转换(合成)为语音
- CRM如何提高IT公司的利率
- 如何在Node.js中使用nodemailer发送电子邮件(gmail,Outlook和Zoho)
- 最新的Zoom安全漏洞(你需要了解的内容)
- 地理编码将如何塑造未来的技术和服务
- 使你的网站闪电般飞速的10条性能提示
- 详解Apache Dubbo的SPI实现机制