This article mainly introduces Node. in js, the event transmitter mode is used to implement event binding. This article also explains the basic knowledge of callback mode, transmitter mode, and event type. For more information, see Node, many objects launch events. For example, a TCP server will launch a "connect" event whenever a client requests a connection. For example, the file system will launch a "data" event every time a whole piece of data is read. These objects are called event emitter in Node ). Event transmitters allow programmers to subscribe to events they are interested in and bind callback functions to related events so that the callback function is called whenever an event transmitter sends an event. The publishing/subscription mode is very similar to the traditional GUI mode. For example, when a button is clicked, the program will receive the corresponding notification. In this mode, the server program can respond to some events, such as client connections, available data on the socket, or when the file is closed.
You can also create your own event transmitters. In fact, Node provides an EventEmitter pseudo class that can be used as a base class to create your own event transmitters.
Understanding callback Mode
Asynchronous programming does not use the function return value to indicate the end Of the function call, but uses the subsequent transmission style.
The "next transfer style" (CPS: Continuation-passing style) is a programming style in which process control is explicitly passed to the next operation ......
A CPS-style function accepts a function as an additional parameter. This function is used to explicitly point out the next Flow controlled by the program. When the CPS function calculates its "return value ", it calls the function that represents the next process of the program and uses the "return value" of the CPS function as its parameter.
From Wikipedia-http://en.wikipedia.org/wiki/Continuation-passing_style
In this programming style, each function will call a callback function after execution, so that the program can continue to run. You will understand later that JavaScript is very suitable for this programming style. Below is an example of loading files to memory under a Node:
The Code is as follows:
Var fs = require ('fs ');
Fs. readFile ('/etc/passwd', function (err, fileContent ){
If (err ){
Throw err;
}
Console. log ('file content', fileContent. toString ());
});
In this example, you pass an inline anonymous function as fs. the second parameter of readFile is actually using CPS programming, Because you handed over the subsequent process of program execution to the callback function.
As you can see, the first parameter of the callback function is an Error object. If a program Error occurs, this parameter will be an Error instance, this is a common pattern for CPS programming in Node.
Understanding event transmitter Mode
In the standard callback mode, a function is passed as a parameter to the function to be executed. This mode works well when the client needs to be notified after the function is completed. However, this mode is not suitable if multiple events or repeated events occur during function execution. For example, if you want to get a notification every time the socket receives the available data, you will find that the standard callback mode is not very useful, and the event transmitter mode will be used in this case, you can use a set of standard interfaces to clearly separate the event generator and event listener.
When the event generator mode is used, two or more objects-event transmitters and one or more event listeners are involved.
An event transmitter, as its name implies, is an object that can generate events. The event listener is the code bound to the event transmitter to listen to specific types of events, as shown in the following example:
The Code is as follows:
Var req = http. request (options, function (response ){
Response. on ("data", function (data ){
Console. log ("some data from the response", data );
});
Response. on ("end", function (){
Console. log ("response ended ");
});
});
Req. end ();
This Code demonstrates the two steps required to use Node's http. request API (see the following section) to create an HTTP request to access a remote HTTP server. The first line uses the "next transmission style" (CPS: Continuation-passing style), passing an inline function that will be called when the HTTP response is made. The HTTP request API uses CPS here because the program continues to perform subsequent operations after the http. request function is executed.
When http. after the request is executed, the anonymous callback function is called and the HTTP Response object is passed as a parameter. The HTTP Response object is an event transmitter. According to the Node documentation, it can launch many events including data and end. The callback functions you register will be called every time an event occurs.
As an experience, when you need to re-obtain the execution right after the requested operation is complete, use the CPS mode, and use the event transmitter mode when the event can occur multiple times.
Understanding event types
Each event to be fired has a string type. The preceding example contains two event types: "data" and "end". They are arbitrary strings defined by the event transmitter, generally, the event type is composed of lowercase words that do not contain null characters.
Code cannot be used to determine the types of events that event transmitters can generate, because the event transmitter API does not have an internal mechanism, therefore, the API you are using should have documentation to indicate which types of events it can launch.
Once an event occurs, the event transmitter will call the Event-related listener and pass the relevant data as a parameter to the listener. In front of http. in the request example, the "data" Event Callback Function accepts a data object as its first and only parameter, while "end" does not accept any data, these parameters, as part of the API contract, are also defined by the API creator. The Parameter Signatures of these callback functions are also described in the API documentation of each event transmitter.
Although the event transmitter serves all types of events, the "error" event is a special implementation in Node. Most event transmitters in Node generate an "error" event when a program error occurs. If the program does not listen to the "error" event of an event transmitter, the event transmitter will notice and throw an uncaptured exception when an error occurs.
You can run the following code in Node PERL to test the effect. It simulates an event transmitter that can generate two types of events:
The Code is as follows:
Var em = new (require ('events'). EventEmitter )();
Em. emit ('event1 ');
Em. emit ('error', new error ('My mistoke '));
You will see the following output:
The Code is as follows:
Var em = new (require ('events'). EventEmitter )();
Undefined
> Em. emit ('event1 ');
False
> Em. emit ('error', new error ('My mistoke '));
Error: My mistake
At repl: 1: 18
At REPLServer. eval (repl. js: 80: 21)
At repl. js: 190: 20
At REPLServer. eval (repl. js: 87: 5)
At Interface. (repl. js: 182: 12)
At Interface. emit (events. js: 67: 17)
At Interface. _ onLine (readline. js: 162: 10)
At Interface. _ line (readline. js: 426: 8)
At Interface. _ ttyWrite (readline. js: 603: 14)
At ReadStream. (readline. js: 82: 12)
>
Line 3 of the Code launches an event named "event1" without any effect. However, when an "error" event is triggered, the error is thrown to the stack. If the program is not running in the PERL Command Line environment, the program will crash due to uncaptured exceptions.
Use the event transmitter API
Any object that implements the event transmitter mode (such as TCP Socket and HTTP request) implements the following methods:
The Code is as follows:
. AddListener and. on -- add event listeners for specified types of events
. Once -- bind an event listener that only executes once for a specified type of event
. RemoveEventListener -- delete a listener bound to a specified event
. RemoveAllEventListener -- delete all listeners bound to a specified event
Next we will introduce them in detail.
Use. addListener () or. on () to bind the callback function.
By specifying the event type and callback function, you can register the operations performed when an event occurs. For example, if a data block is available when a file reads data streams, a "data" event will be triggered, the following code shows how to pass in a callback function to let the program tell you that a data event has occurred.
The Code is as follows:
Function receiveData (data ){
Console. log ("got data from file read stream: % j", data );
}
ReadStream. addListener ("data", receiveData );
You can also use. on, which is just a shorthand for. addListener. The following code is the same as the above Code:
The Code is as follows:
Function receiveData (data ){
Console. log ("got data from file read stream: % j", data );
}
ReadStream. on ("data", receiveData );
The previous Code uses a previously defined namefunction as the callback function. You can also use an inline anonymous function to simplify the Code:
The Code is as follows:
ReadStream. on ("data", function (data ){
Console. log ("got data from file read stream: % j", data );
});
As mentioned above, the number of parameters and signatures passed to the callback function depend on the specific event transmitter objects and event types. They are not standardized, the "data" event may be a data buffer object, and the "error" event will be an error object. The "end" event of the data stream will not pass any data to the event listener.
Bind multiple Event Listeners
The event transmitter mode allows multiple event listeners to listen to the same event type of the same event transmitter. For example:
The Code is as follows:
I have some data here.
I have some data here too.
The event transmitter is responsible for calling all listeners bound to the specified event type in the order of listener registration, that is:
1. When an event occurs, the event listener may not be called immediately, and other event listeners may be called before it.
2. it is abnormal to throw an exception to the stack. It may be because there is a bug in the Code. When an event is fired, if an event listener throws an exception when it is called, some event listeners may never be called. In this case, the event transmitter will capture an exception and may also handle it.
Let's look at the example below:
The Code is as follows:
ReadStream. on ("data", function (data ){
Throw new Error ("Something wrong has happened ");
});
ReadStream. on ("data", function (data ){
Console. log ('I have some data here too .');
});
Because the first listener throws an exception, the second listener is not called.
Remove an event listener from the event transmitter with. removeListener ()
If you no longer care about an event of an object, you can cancel the registered event listener by specifying the event type and callback function, as shown in the following code:
The Code is as follows:
Function receiveData (data ){
Console. log ("got data from file read stream: % j", data );
}
ReadStream. on ("data", receiveData );
//...
ReadStream. removeListener ("data", receiveData );
In this example, the last line removes an event listener that may be called at any time in the future from the event transmitter object.
To delete a listener, you must name the callback function because the name of the callback function is required during addition and deletion.
Use. once () to make the callback function run at most once
If you want to listen to an event that can be executed at most once, or you are only interested in the first occurrence of an event, you can use the. once () function:
The Code is as follows:
Function receiveData (data ){
Console. log ("got data from file read stream: % j", data );
}
ReadStream. once ("data", receiveData );
In the above Code, the receiveData function is called only once. If the readStream object launches a data event, the receiveData callback function will be triggered only once.
It is actually a convenient method, because it can be implemented very easily, like this:
The Code is as follows:
Var EventEmitter = require ("events"). EventEmitter;
EventEmitter. prototype. once = function (type, callback ){
Var that = this;
This. on (type, function listener (){
That. removeListener (type, listener );
Callback. apply (that, arguments );
});
};
In the code above, you reset the EventEmitter. prototype. once function, and also redefine the once function of each object inherited from EventEmitter. The Code simply uses the. on () method. Once an event is received, use. removeEventListener () to cancel the registration of the callback function and call the original callback function.
Note: The function. apply () method is used in the previous Code. It accepts an object and uses it as the included this variable and an array of parameters. In the preceding example, the unmodified parameter array is transparently transmitted to the callback function through the event transmitter.
Remove all event listeners from the event transmitter with. removeAllListeners ()
You can remove all listeners registered to the specified event type from the event transmitter as follows:
The Code is as follows:
Emitter. removeAllListeners (type );
For example, you can cancel the listener of all process interrupt signals as follows:
The Code is as follows:
Process. removeAllListeners ("SIGTERM ");
Note: As an experience, we recommend that you use this function only when you know exactly what is deleted. Otherwise, you should let other parts of the application Delete the event listener set, you can also remove the listener for those parts of the program. However, in some rare scenarios, this function is still very useful, for example, when you are preparing to close an event transmitter in an orderly manner or close the entire process.
Create an event Transmitter
The event transmitter makes the programming interface more universal in a great way. In a common and easy-to-understand programming mode, the client directly calls various functions. In the event transmitter mode, the client is bound to various events, which makes your program more flexible. (Note: The event emitter provides a great way of making a programming interface more generic. when you use a common understood pattern, clients bind to events instead of invoking functions, making your program more flexible .)
In addition, you can obtain many features by using event transmitters, such as binding multiple irrelevant listeners to the same event.
Inherit from Node event Transmitter
If you are interested in the Node event transmitter mode and intend to use it in your own applications, you can create a pseudo class by inheriting EventEmitter:
The Code is as follows:
Util = require ('til ');
Var EventEmitter = require ('events'). EventEmitter;
// This is the constructor of MyClass:
Var MyClass = function (){
}
Util. inherits (MyClass, EventEmitter );
Note: util. inherits establishes the prototype chain of MyClass so that your MyClass instance can use the original EventEmitter method.
Launch Event
By inheriting from EventEmitter, MyClass can launch events like this:
The Code is as follows:
MyClass. prototype. someMethod = function (){
This. emit ("custom event", "argument 1", "argument 2 ");
};
In the above Code, when the someMethond method is called by an instance of MyClass, an event called "cuteom event" will be launched, and two strings will be sent as data: "argument 1" and "argument 2" are passed as parameters to the event listener.
The client of the MyClass instance can listen to the "custom event" event as follows:
The Code is as follows:
Var myInstance = new MyClass ();
MyInstance. on ('customevent', function (str1, str2 ){
Console. log ('Got a custom event with the str1 % s and str2 % s! ', Str1, str2 );
});
For example, you can create a Ticker class that launches a "tick" event every second:
The Code is as follows:
Var util = require ('til '),
EventEmitter = require ('events'). EventEmitter;
Var Ticker = function (){
Var self = this;
SetInterval (function (){
Self. emit ('tick ');
},1000 );
};
Util. inherits (Ticker, EventEmitter );
Clients using the Ticker class can demonstrate how to use the Ticker class and listen for "tick" events,
The Code is as follows:
Var ticker = new Ticker ();
Ticker. on ("tick", function (){
Console. log ("tick ");
});
Summary
The event transmitter mode is recurrent pattern, which can be used to decouple an event transmitter object from the code of a group of specific events.
You can use event_emitter.on () to register listeners for specific types of events and use event_emitter.removeListener () to cancel registration.
You can also create your own event transmitters by inheriting EventEmitter and simply using the. emit () function.