Node.js is an emerging backend language designed to help programmers quickly build scalable applications. Node.js has many attractive features, and there are countless reports about it. This article will analyze and discuss the features of EventEmitter, Streams, Coding Style, Linting, Coding Style and other to help users have a deeper understanding of Node.js.
As a platform built on the Chrome JavaScript runtime, our relevant understanding of JavaScript seems to be applicable to node applications; without additional language extensions or modifications, we can apply the experience of front-end programming to back-end programming.
EventEmitter (event sender)
First of all, you should understand the EventEmitter model. It can send an event as well as an event that will interest the consumer. We can think of it as an extension of the callback pass pattern to an asynchronous function. In particular, EventEmitter will have a more advantage when multiple callbacks are required.
For example, a caller sends a "list file" request to the remote server. You may want to group the returned results and perform a callback for each group. The EventEmitter model allows you to send "file" callbacks on each group and perform "end" processing when all operations are completed.
When using EventEmitter, just set the relevant events and parameters.
The code copy is as follows:
var EventEmitter = require('events').EventEmitter;
var util = require('util');
function MyClass() {
if (!(this instanceof MyClass)) return new MyClass();
EventEmitter.call(this);
var self = this;
setTimeout(function timeoutCb() {
self.emit('myEvent', 'hello world', 42);
}, 1000);
}
util.inherits(MyClass, EventEmitter);
The MyClass constructor creates a time trigger with a trigger delay of 1s and a trigger event of myEvent. To use related events, you need to execute the on() method:
The code copy is as follows:
var myObj = new MyClass();
var start = Date.now();
myObj.on('myEvent', function myEventCb(str, num) {
console.log('myEvent triggered', str, num, Date.now() - start);
});
It should be noted here that although the subscribed EventEmitter event is an asynchronous event, when time triggers, the listener's actions will be synchronized. Therefore, if the above myEvent event has 10 listeners, all listeners will be called in order without waiting for the event loop.
If a subclass of EventEmitter generates an emit('error') event, but no listener subscribes to it, the EventEmitter base class throws an exception, causing an uncaughtException event to be triggered when the process object is executed.
verror
verror is an extension of the base class Error, which allows us to define output messages using the printf character format.
Streams
If there is a very large file that needs to be processed, the ideal method should be to read part and write part. No matter how big the file is, it will always be processed as long as time allows. This requires the concept of streaming. Streams is another widely used model in Node, in Node, an implementation of EventEmitter. Provides readable, writable or full duplex interfaces. It is an abstract interface, and the regular operation events provided include: readable, writable, drain, data, end and close. If we can use pipelines to effectively integrate these events, more powerful interactions will be achieved.
By using .pipe(), Note can communicate with back-pressure through pipeline. Back-pressure means: only those that can be written, or only those that can be read.
For example, we now send data from stdin to a local file and remote server:
The code copy is as follows:
var fs = require('fs');
var net = require('net');
var localFile = fs.createWriteStream('localFile.tmp');
net.connect('255.255.255.255', 12345, function(client) {
process.stdin.pipe(client);
process.stdin.pipe(localFile);
});
And if we want to send data to a local file and want to use gunzip to compress this stream, we can do this:
The code copy is as follows:
var fs = require('fs');
var zlib = require('zlib');
process.stdin.pipe(zlib.createGunzip()).pipe(fs.createWriteStream('localFile.tar'));
If you want to know more about stream, please click here.
Control Flow (process control)
Since JS has functional concepts such as first-class objects, closures, etc., it is possible to easily define callback permissions. This is very convenient when prototyping, and can integrate logical permissions on demand. But it is easy to use clumsy built-in functions.
For example, we want to read a series of files in order and then perform a task:
The code copy is as follows:
fs.readFile('firstFile', 'utf8', function firstCb(err, firstFile) {
doSomething(firstFile);
fs.readFile('secondFile', 'utf8', function secondCb(err, secondFile) {
doSomething(secondFile);
fs.readFile('thirdFile', 'utf8', function thirdCb(err, thirdFile) {
doSomething(thirdFile);
});
});
});
The problems with this pattern are:
1. The logic of these codes is very scattered and disorderly, and the related operational processes are difficult to understand.
2. No errors or exceptions are handled.
3. Closure memory leaks in JS are very common and difficult to diagnose and detect.
If we want to perform a series of asynchronous operations on an input set, using a process control library is a smarter choice. vasync is used here.
vasync is a process control library whose ideas come from asynchronous operations. What makes it special is that it allows consumers to view and observe a certain task process. This information is very useful for studying the process of a certain error.
Coding Style (programming style)
Programming style is the most controversial topic because it is often casual. Everyone has their own preferences. It is important to find a style that suits individuals and teams. Some traditional heritage may make the Node development journey a better place.
1. Name the function
2. Try to name all functions.
3. Avoid closures
4. Do not define other functions in a certain function. This reduces many unexpected closure memory leak accidents.
5. More and smaller functions
Although V8 JIT is a powerful engine, smaller and thinner functions will be better combined with V8. Furthermore, if our functions are all small and exquisite (about 100 lines), we will also thank ourselves when reading and maintaining them ourselves.
Check style programmatically: Maintain style consistency and use a checking tool to enhance it. We are using jsstyle.
Linting (code check)
The Lint tool can perform static analysis of the code without running, checking for potential errors and risks, such as missing break statements in caseswitch. Lint is not simply equivalent to style checking, it is more aimed at objective risk analysis rather than subjective style choices. We use javascriptlint, which has rich check items.
Logging (logging)
When we are programming and coding, we need to have a long-term vision. In particular, consider what tools to use for debugging. The excellent first step is to do effective logging. We need to identify the information and see what is paid special attention to during debugging and what is used for analysis and research at runtime. It is recommended to use Bunyan, a direct Node.js logging library, and the data output format is JSON. For more information, please click here.
Client Server
If an application has distributed processing capabilities, it will be more attractive in the market. Similar interfaces can be described using the HTTP RESTFul API or the original TCP JSON. This allows developers to combine experience on Node with asynchronous network environments, as well as the use of streams with distributed and scalable systems.
Common tools:
1. restify
Simply put, this is a tool for building REST services. It provides good viewing and debugging support, while supporting Bunyan and DTrace.
2. fast
fast is a lightweight tool that uses TCP to process JSON messages. DTrace support is provided, which allows us to quickly identify performance characteristics of server clients.
3. workflow
Workflow is built on restify and can define business processes for a series of remote services and APIs. For example: error status, timeout, reconnection, congestion processing, etc.