分类: Node.js

Using Node’s Event Module






EventEmitter: What and Why

节选自英文原文 – http://dev.tutsplus.com/tutorials/using-nodes-event-module–net-35941

what exactly does the EventEmitter class do?

(EventEmitter class 的作用)
– Put simply, it allows you to listen for “events” and assign actions to run when those events occur.
These are very similar with mouse and keyboard events, except that we can emit events on our own, when we want to, and not necessary based on user interaction. The principles EventEmitter is based on have been called the publish/subscribe model, because we can subscribe to events and then publish them. There are many front-end libraries built with pub/sub support, but Node has it build in.
(简单来说,EventEmitter 监控各种“事件”,好像网页上的鼠标点击,键盘动作等等,然后根据事件驱动相关的”动作“,有了EventEmitter,我们能够构造自己的”事件“,按照”发行/接收“的方式,自由的创建自己的”事件“和”相关动作“)

why would you use the event model?

(为什么用event model?)
– In Node, it’s an alternative to deeply nested callbacks. A lot of Node methods are run asynchronously, which means that to run code after the method has finished, you need to pass a callback method to the function. Eventually, your code will look like a giant funnel. To prevent this, many node classes emit events that you can listen for. This allows you to organize your code the way you’d like to, and not use callbacks.
(由于Node,其实是JavaScript特有的Callback,很多时候,在不同步程序中,你会用来多层callback,一层层内嵌,到最后导致程序很难dubug,所以很多时候,Node class提供了event,你可以直接”订制接收[subscribe]“,然后在事件发生时,执行程序。这样,使得程序更加简单明了,更加结构化)

Using EventEmitter

(下面用一个简单的例子来说明如何运用EventEmitter)

var events = require("events");
var EventEmitter = require("events").EventEmitter;

var ee = new EventEmitter();
ee.on("someEvent", function () {
    console.log("event has occured");
});//加载Event
 
ee.emit("someEvent");//emit Event 
//event has occured

We begin by creating a new EventEmitter object. This object has two main methods that we use for events: on and emit.

on

method takes two parameters:
– name of the event we’re listening for: in this case, that’s “someEvent”. (名字)
– The second parameter is the function that will be called when the event occurs. (function)

emit

Now, to fire the event, you pass the event name to the EventEmitter instance’s emit method. That’s the last line of the code above. If you run that code, you’ll see that we get the text printed out to the console.
(上面建立了一个最简单的EventEmitter,稍加说明,注意On 和 emit
– on 建立event (Publish),建立一个event 要提供2个parameter
– event 的名字(任意名字,这里用的是”someEvent”)
– event 发生后,需要执行的程序功能 (function)
– emit 提示事件发生, 按照名字“someEvent”,找到之前配置的事件,执行配置的function.)
That’s the most basic use of an EventEmitter. You can also include data when firing events:
当然,你也可以传递Event data:

ee.emit("new-user", userObj);
ee.on("new-user", function (data) {
 // use data here (data === userObj)
});

That’s only one data parameter, but you can include as many as you want. To use them in your event handler function, just take them as parameters
(传递多个event data)

ee.emit("new-user", userObj1,userObj2,userObj3);
ee.on("new-user", function (data1,data2,data3) {
    // use data here
});

Before continuing, let me clarify part of the EventEmitter functionality. We can have more than one listener for each event; multiple event listeners can be assigned (all with on), and all functions will be called when the event is fired.
(你可以加入多个event listener,当event fire的时候,所有的event listener都会被启动。
if more are created, node will issue a warning. However, we can change this amount by using setMaxListeners.

ee.on("someEvent", function () { console.log("event 1"); });
ee.on("someEvent", function () { console.log("event 2"); });
ee.on("someEvent", function () { console.log("event 3"); });
ee.on("someEvent", function () { console.log("event 4"); });
ee.on("someEvent", function () { console.log("event 5"); });
ee.on("someEvent", function () { console.log("event 6"); });
ee.on("someEvent", function () { console.log("event 7"); });
ee.on("someEvent", function () { console.log("event 8"); });
ee.on("someEvent", function () { console.log("event 9"); });
ee.on("someEvent", function () { console.log("event 10"); });
ee.on("someEvent", function () { console.log("event 11"); });
ee.setMaxListeners(20); //To set the maximum number of viewers
ee.emit("someEvent");
Other EventEmitter Methods

(另外的一些有用的EventEmitter Methods)
There are a few other EventEmitter methods you’ll find useful.
once (It’s just like the on method, except that it only works once. After being called for the first time, the listener is removed.)

 ee.once("firstConnection", function () { console.log("You'll never see this again"); });
 ee.emit("firstConnection");
 ee.emit("firstConnection");

removeListener (takes two parameters: the event name and the listener function.)

 function onlyOnce () {
    console.log("You'll never see this again");
    ee.removeListener("firstConnection", onlyOnce);
}
 
 ee.on("firstConnection", onlyOnce) 
 ee.emit("firstConnection");
 ee.emit("firstConnection");// Nothing display here
 

removeAllListeners (remove all the listeners bound to a given event)

ee.removeAllListeners("firstConnection");
ee.removeAllListeners(); //remove all listeners for all events

– listener (takes an event name as a parameter and returns an array of all the functions that are listening for that event.)

 function onlyOnce () {
    console.log(ee.listeners("firstConnection"));
    ee.removeListener("firstConnection", onlyOnce);
    console.log(ee.listeners("firstConnection"));
}
 ee.on("firstConnection", onlyOnce) 
 ee.emit("firstConnection");
 ee.emit("firstConnection");
 

the last, EventEmitter instance itself actually fires two events of its own
newListener (emit when we create new listeners )
removeListener (emit when we remove them)
(EventEmitter 自己也会fire up event)

 ee.on("newListener", function (evtName, fn) {
      console.log("New Listener: " + evtName);
 });
	 
 ee.on("removeListener", function (evtName) {
      console.log("Removed Listener: " + evtName);
 });
	 
 function foo () {} 
 ee.on("save-user", foo);
 ee.removeListener("save-user", foo);

Running this, you’ll see our listeners for both new listeners and removed listeners have been run, and we get the messages we expected.

EventEmitter Inside Modules

(如何在自己的module里面,建立Event)
Actually, there are built-in Node modules create EventEmitter instances, and use them to handle internal events. For example, you may be familiar with the http module; this is the module that you’ll use to create a web server. This basic example shows how the on method of the EventEmitter class has become part of the http.Server class:
其实在一些module里面,也自己建立的Event功能,比如”http” module,下面的例子演示了,EventEmitter class 下的on,是如何用于http.server class里面的。

 var http = require("http");
 var server = http.createServer();
	 
 server.on("request", function (req, res) {
       res.end("this is the response");
 });	 
 server.listen(3000);

If you run this snippet, the process will wait for a request; you can go to http://localhost:3000 and you’ll get the response. When the server instance gets the request from your browser, it emits a “request” event, an event that our listener will receive and can act upon.
(每次,用户发送request 到”http://localhost:3000″,server.listen就会fire request event,然后server.on下的request event 就会被启动,然后运行后面的function)

creating a class that will inherit from EventEmitter

(自己建立自己的class继承EventEmitter)
We’ll create a simple UserList class, which handles user objects. So, in a userlist.js file, we’ll start with this:

var util = require("util"); 
//util module to help with the inheriting
var EventEmitter = require("events").EventEmitter;
//Dummy database
var id = 1;
var database = {
    users: [
        { id: id++, name: "Joe Smith",  occupation: "developer"    },
        { id: id++, name: "Jane Doe",   occupation: "data analyst" },
        { id: id++, name: "John Henry", occupation: "designer"     }
    ]
};
function UserList () {
    EventEmitter.call(this);
}
/*
constructor function,
using the call method on the EventEmitter constructor to run that method on the new UserList object (which is "this")
*/

util.inherits(UserList, EventEmitter);
/*
This will add everything that's on EventEmitter.prototype to UserList.prototype; now, our UserList instances will have all the methods of an EventEmitter instance
*/

UserList.prototype.save = function (obj) {
    obj.id = id++;
    database.users.push(obj);
    this.emit("saved-user", obj); 
    //(when call UserList.save -> emit "saved-user" function and pass obj as data) 
};

UserList.prototype.all = function () {
    return database.users;
};
 
module.exports = UserList;

Now, let’s see this in use; in another file, say test.js. Add the following:

var UserList = require("./userlist");
var users = new UserList();
 
users.on("saved-user", function (user) {
    console.log("saved: " + user.name + " (" + user.id + ")");
});
 
users.save({ name: "Jane Doe", occupation: "manager" });
users.save({ name: "John Jacob", occupation: "developer" });

//saved: Jane Doe (4)
//saved: John Jacob (5)




发表评论

Webmentions

  • 自建NodeJS-聊天室(Socket.IO) | Ian's Blog

    […] socket.io通过event.on 和 evnet.emit来进行交流,之前我写个一个关于node event的文章可以参考。 […]