Node. js advanced programming: using JavaScript to build scalable applications (5) 2.5 using event transmitter mode to simplify event binding

Source: Internet
Author: User
Tags emit
Document directory
  • Understanding callback Mode
  • Understanding event transmitter Mode
  • Understanding event types
  • Use the event transmitter API
  • Create an event Transmitter

For the list of articles in this series and the translation progress, see Node. js advanced programming: using Javascript to build scalable applications (〇)

This article corresponds to the first part of the original article, Chapter 5: Node Core API Basics: Using the Event Emitter Pattern

Copy the article from Word here, especially the indentation is not the same as the original text. You can click here to download the PDF version of this article.

Chapter 5: simplify event binding in event transmitter mode in this chapter:
  • Introduction to Event Emitter Pattern
  • Binding and cancellation of Event Listeners
  • Create your own event Transmitter

 

In Node, many objects will 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.

"Subsequent transmission style" (CPS:Continuation-passing style)It is a programming style, and process control is passed explicitly to the next operation ......

CPSA 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 CPSFunction compute its "return value", it will call the function that represents the next process of the program, andThe "return value" of the function is used 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:

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:

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:

Var em = new (require ('events'). EventEmitter )();

Em. emit ('event1 ');

Em. emit ('error', new error ('My mistoke '));

You will see the following output:

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. <anonymous> (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. <anonymous> (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:

  • . 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.

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:

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:

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:

ReadStream. on ("data", function (data ){

Console. log ('I have some data here .');

});

ReadStream. on ("data", function (data ){

Console. log ('I have some data here too .');

});

In this example, two functions are bound to the "data" Event Type of readStream. Each time the readStream object initiates a "data" event, you will see the following output:

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:

  • When an event occurs, the event listener may not be called immediately, and other event listeners may be called before it.
  • 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:

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:

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:

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:

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: function. apply () is used in the previous code ()Method, which accepts an object and uses it as the contained thisVariable and a parameter array. 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:

Emitter. removeAllListeners (type );

For example, you can cancel the listener of all process interrupt signals 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:

Util = require ('til ');

Var EventEmitter = require ('events'). EventEmitter;

//This is MyClassConstructor:

Var MyClass = function (){

}

Util. inherits (MyClass, EventEmitter );

Note: util. inheritsCreated MyClassMakes your MyClassThe instance can use EventEmitter.

Launch Event

By inheriting from EventEmitter, MyClass can launch events like this:

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:

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:

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,

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.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.