Node.js Tutorial from Coding compiler. This is a very comprehensive Node tutorial for beginners covering topics like Node introduction, installation, nvm version management tool, repl environment, global objects, modular structure and exception handling. Let’s start learning Node.js.
Table of Contents
- Introduction
- Installation and update
- Version management tool nvm
- Basic usage
- REPL environment
- Asynchronous operation
- Global objects and global variables
- Modular structure
- Overview
- Core module
- Custom module
- Exception handling
- Try…catch structure
- Callback
- Error event of the EventEmitter interface
- UncaughtException event
- unhandledRejection event
- Command line script
Node.js Introduction
Node is the server runtime environment for the JavaScript language.
The so-called “runtime environment” has two meanings: First, the JavaScript language runs on the server through Node. In this sense, Node is a bit like a JavaScript virtual machine.
Second, Node provides a large number of tool libraries to make the JavaScript language interact with the operating system (such as reading Write files, create new subprocesses, and in this sense, Node is a tool library for JavaScript.
Node internally uses Google’s V8 engine as a JavaScript language interpreter; calls operating system resources through a self-developed libuv library.
Node.js Installation and update
Visit the official website nodejs.org or github.com/nodesource/distributions to see the latest version of Node and how to install it.
The official website provides compiled binary packages, which can be extracted under the /usr/local directory.
$ tar -xf node-someversion.tgz
Then, create symbolic links and add them to the path inside the $PATH variable.
$ ln -s /usr/local/node/bin/node /usr/local/bin/node
$ ln -s /usr/local/node/bin/npm /usr/local/bin/npm
Below is the installation method for installing the Deb package under Ubuntu and Debian.
$ curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash -
$ sudo apt-get install -y nodejs
$ apt-get install nodejs
After the installation is complete, run the following command to see if it works.
$ node --version
# or
$ node -v
Updating the node.js version can be done through the n module of node.js.
$ sudo npm install n -g
$ sudo n stable
The above code n updates the node.js to the latest released stable version through the module.
N Modules can also specify to install a specific version of node.
$ sudo n 0.10.21
Version management tool nvm
If you want to install multiple versions of node.js on the same machine at the same time, you need to use the version management tool nvm.
$ git clone https://github.com/creationix/nvm.git ~/.nvm
$ source ~/.nvm/nvm.sh
After installation, the nvm execution script should be activated before each use. It is recommended to add it to the ~/.bashrc file (assuming Bash is used). Once activated, you can install the specified version of Node.
# Install the latest version
$ nvm install node
# Install the specified version
$ nvm install 0.12.1
# Use the latest version installed
$ nvm use node
# Use the specified version of node
$ nvm use 0.12
Nvm also allows access to the specified version of the REPL environment.
$ nvm run 0.12
If you create a new .nvmrc file in the project root directory and write the version number, just enter the nvm use command and no longer need to add the version number.
Below are other commands that are often used.
# View all versions of the local installation
$ nvm ls
# View all available versions of the server.
$ nvm ls-remote
# Exit the activated nvm and use the deactivate command.
$ nvm deactivate
Basic usage
After the installation is complete, run the node.js program, which is to use the node command to read the JavaScript script.
The demo.js script file of the current directory can be executed like this.
$ node demo
# or
$ node demo.js
-eCode parameters can be executed using parameters.
$ node -e 'console.log("Hello World")'
Hello World
REPL Environment
Type the node command on the command line, followed by no file name, enter a Node.js REPL environment (Read-eval–print loop, “read-evaluate-output” loop), you can run a variety of JavaScript commands directly.
$ node
> 1+1
2
>
If the parameter –use_strict is used, the REPL will run in strict mode.
$ node --use_strict
REPL is a shell that Node.js interacts with the user. Various basic shell functions can be used inside, such as using the up and down arrow keys to traverse commands that have been used.
The special variable underscore (_) indicates the result of the previous command.
> 1 + 1
2
> _ + 1
3
In the REPL, if you run an expression, the result is returned directly on the command line. If you run a statement, there will be no output because the statement has no return value.
> x = 1
1
> var x = 1
The second command of the above code does not show any results. Because this is a statement, not an expression, there is no return value.
Asynchronous operation
Node uses the V8 engine to process JavaScript scripts. The biggest feature is that it runs in a single thread and can only run one task at a time. This causes Node to use a large number of asynchronous operations, that is, the task is not executed immediately, but inserted at the end of the task queue, and then executed after the previous task is run.
Due to this feature, subsequent operations of a task are often defined in the form of a callback.
var isTrue = function(value, callback) {
if (value === true) {
callback(null, "Value was true.");
}
else {
callback(new Error("Value is not true!"));
}
}
The above code passes the further processing to the callback function callback.
The Node convention, if a function requires a callback function as a parameter, the callback function is the last parameter. In addition, the first parameter of the callback function itself is the error object passed in the previous step.
var callback = function (error, value) {
if (error) {
return console.log(error);
}
console.log(value);
}
In the above code, the first parameter of the callback is the Error object, and the second parameter is the real data parameter. This is because the callback function is mainly used for asynchronous operations.
When the callback function runs, the previous operation ends early, and the wrong execution stack does not exist anymore. The traditional error trapping mechanism try…catch does not work for asynchronous operations, so only Can give the error to the callback function processing.
try {
db.User.get(userId, function(err, user) {
if(err) {
throw err
}
// ...
})
} catch(e) {
console.log(‘Oh no!’);
}
In the above code, the db.User.get method is an asynchronous operation. When the error is thrown, the try…catch block in which it is located may have finished running, which will cause the error to be caught. Therefore, Node uniformly stipulates that once an asynchronous operation has an error, the error object is passed to the callback function.
If no error occurs, the first argument to the callback function passes in null. This kind of writing has a great advantage, that is, as long as you judge the first parameter of the callback function, you know if there is any error. If it is not null, it will definitely be wrong. In addition, this can also pass errors in layers.
if(err) {
// In addition to letting go of the No Permission error, other errors are passed to the next callback function.
if(!err.noPermission) {
return next(err);
}
}
Global objects and global variables
Node provides the following global objects, which are called by all modules.
- Global : indicates the global environment where Node is located, similar to the window object of the browser. It should be noted that if you declare a global variable in the browser, it actually declares the properties of a global object, such as the var x = 1 same as the setting window.x = 1, but Node is not like this, at least not in the module (the behavior of the REPL environment and the browser consistent).
- In the module file, declare var x = 1 that the variable is not an global object’s property and global.xis equal to undefined. This is because the global variables of the module are private to the module and cannot be retrieved by other modules.
- Process : This object represents the current process in which the Node is located, allowing developers to interact with the process.
- Console : Point to the built-in Console module of Node to provide standard input and standard output functions in the command line environment.
Node also provides some global functions.
- setTimeout() : Used to run the callback function after the specified number of milliseconds. The actual call interval also depends on system factors. The number of milliseconds between the intervals is between 1 millisecond and 2,147,483,647 milliseconds (about 24.8 days). If it exceeds this range, it will be automatically changed to 1 millisecond. This method returns an integer representing the number of this new timer.
- clearTimeout() : Used to terminate a timer created by a setTimeout method.
- setInterval() : Used to call the callback function every certain millisecond. Due to system factors, it may not be possible to guarantee exactly the number of milliseconds between each call, but only more than this interval, not less than it. The specified number of milliseconds must be an integer between 1 and 2,147,483,647 (approximately 24.8 days), and if it exceeds this range, it will be automatically changed to 1 millisecond. This method returns an integer representing the number of this new timer.
- clearInterval() : Terminates a timer created with the setInterval method.
- Require() : Used to load the module.
- Buffer() : Used to manipulate binary data.
Node provides two global variables, all starting with two underscores.
- __filename: Point to the name of the currently running script file.
- __dirname: Point to the directory where the currently running script is located.
In addition, there are some objects that are actually local variables inside the module. The objects pointed to are different according to the module, but all modules are applicable. They can be regarded as pseudo-global variables, mainly module, module.exports, exports. Wait.
Modular Structure Overview
Node.js uses a modular structure that defines and uses modules in accordance with the CommonJS specification . The module and the file have a one-to-one correspondence, that is, loading a module, in fact, is loading a corresponding module file.
The require command is used to specify the load module. The suffix name of the script file can be omitted when loading.
var circle = require('./circle.js');
// or
var circle = require('./circle');
The argument to the require method is the name of the module file. It is divided into two cases. The first case is that the parameter contains the file path (such as the above example).
In this case, the path is relative to the directory where the current script is located. In the second case, the file path is not included in the parameter. The installation directory of the module, to find the installed modules (such as the following example).
var bar = require('bar');
Sometimes a module is itself a directory with multiple files. At this time, Node looks for the module entry file specified by the main attribute in the package.json file.
{
"name" : "bar",
"main" : "./lib/bar.js"
}
In the above code, the module’s startup file is bar.js in the lib subdirectory. When require(‘bar’)the module is loaded with a command, the ./node_modules/bar/lib/bar.js file is actually loaded . The following method will have the same effect.
var bar = require('bar/lib/bar.js')
If there is no package.json file in the module directory, node.js will try to find the index.js or index.node file in the module directory for loading.
Once the module is loaded, it is cached by the system. If the module is loaded the second time, the version in the cache is returned, which means that the module will only be executed once.
If you want the module to execute multiple times, you can have the module return a function and then call the function multiple times.
Core Module
If you just run JavaScript code on the server, it’s not very useful, because there are many different server scripting languages. The usefulness of Node.js is that it also provides a set of functional modules that interact with the operating system. These core functional modules can be used without installation. Below is a list of them.
- Http : Provides HTTP server functionality.
- Url : Parse the URL.
- Fs : Interact with the file system.
- Querystring : A query string that parses the URL.
- Child_process : New child process.
- Util : Provides a set of useful gadgets.
- Path : Process the file path.
- Crypto : provide encryption and decryption functions, in essentially OpenSSL packaging.
The above core modules, the source code is in the lib subdirectory of Node. In order to improve the speed, they will be compiled into binary files when they are installed.
The core module is always loaded with the highest priority. If you write an HTTP module yourself, require(‘http’)the kernel module is loaded.
Custom Module
The Node module uses the CommonJS specification. As long as this specification is met, the module can be customized.
Here is the simplest module, assuming you create a new foo.js file and write the following.
// foo.js
module.exports = function(x) {
console.log(x);
};
The above code is a module that outputs a method externally via the module.exports variable.
The use of this module is as follows.
// index.js
var m = require('./foo');
m("This is a custom module");
The above code loads the module file foo.js (the suffix is omitted) by the require command, outputs the module’s external interface to the variable m, and then calls m. At this point, run index.js on the command line and the screen will output “This is a custom module.”
$ node index
This is a custom module
The module variable is the top-level variable of the entire module file, and its exports attribute is the interface that the module outputs to the outside. If you directly output a function (like foo.js above), then calling the module is calling a function. However, the module can also output an object. The following is a rewrite of foo.js.
// foo.js
var out = new Object();
function p(string) {
console.log(string);
}
out.print = p;
module.exports = out;
The above code indicates that the module outputs an out object that has a print attribute that points to a function. Below is how to use this module.
// index.js
var m = require('./foo');
m.print("This is a custom module");
The above code indicates that since the specific method is defined on the print property of the module, the print property must be explicitly called.
Exception Handling
Node is a single-threaded runtime environment. Once the thrown exception is not caught, it will cause the entire process to crash. Therefore, Node’s exception handling is very important to ensure the stable operation of the system.
In general, Node has three methods to propagate an error.
- Throw an error object using the throw statement, which throws an exception.
- The error object is passed to the callback function, which is responsible for issuing the error.
- Issue an error event via the EventEmitter interface.
Try…catch structure
The most common way to catch exceptions is to use the try…catch structure. However, this structure cannot catch exceptions thrown by code that is running asynchronously.
try {
process.nextTick(function () {
throw new Error("error");
});
} catch (err) {
//can not catch it
console.log(err);
}
try {
setTimeout(function(){
throw new Error("error");
},1)
} catch (err) {
//can not catch it
console.log(err);
}
The above code uses the process.next Tick and setTimeout methods to throw two exceptions in the next round of event loops, representing the errors thrown by the asynchronous operation. None of them can be caught by the catch block, because the part of the catch block is already running.
One workaround is to put the error capture code into asynchronous execution.
function async(cb, err) {
setTimeout(function() {
try {
if (true)
throw new Error("woops!");
else
cb("done");
} catch(e) {
err(e);
}
}, 2000)
}
async(function(res) {
console.log("received:", res);
}, function(err) {
console.log("Error: async threw an exception:", err);
});
// Error: async threw an exception: Error: woops!
In the above code, the async function throws an error asynchronously, which can be deployed in the asynchronous catch block capture.
Both of these treatment methods are less than ideal. In general, Node only uses try/catch statements in a few cases, such as using JSON.parse parsed JSON text.
Callback
The method used by Node is to pass the error object as the first parameter and pass it into the callback function. This avoids the problem of capturing code that is not in the same time period as the code that caused the error.
fs.readFile('/foo.txt', function(err, data) {
if (err !== null) throw err;
console.log(data);
});
The above code indicates that reading a file foo.txt is an asynchronous operation. Its callback function has two parameters, the first one is the error object, and the second is the file data read. If the first argument is not null, it means that an error has occurred and the code is no longer executed.
Below is a complete example.
function async2(continuation) {
setTimeout(function() {
try {
var res = 42;
if (true)
throw new Error("woops!");
else
continuation(null, res); // pass 'null' for error
} catch(e) {
continuation(e, null);
}
}, 2000);
}
async2(function(err, res) {
if (err)
console.log("Error: (cps) failed:", err);
else
console.log("(cps) received:", res);
});
// Error: (cps) failed: woops!
In the above code, the first argument to the callback function of the async2 function is an error object, which is to handle the error thrown by the asynchronous operation.
Error Event of the EventEmitter Interface
When an error occurs, you can also use the EventEmitter interface to throw an error event.
var EventEmitter = require('events').EventEmitter;
var emitter = new EventEmitter();
emitter.emit('error', new Error('something bad happened'));
Care must be taken to use the above code, because deploying a listener function for an error event can cause the entire application to crash. Therefore, it is always necessary to deploy the following code at the same time.
emitter.on('error', function(err) {
console.error('Error:' + err.message);
});
UncaughtException event
When an exception is not caught, an uncaughtException event is fired, and the event can be registered with the callback function to catch the exception.
var logger = require('tracer').console();
process.on('uncaughtException', function(err) {
console.error('Error caught in uncaughtException event:', err);
});
try {
setTimeout(function(){
throw new Error("error");
},1);
} catch (err) {
//can not catch it
console.log(err);
}
As long as the callback is configured for uncaughtException, the Node process will not exit abnormally, but the context of the exception has been lost, and the details of the exception cannot be given.
Moreover, an exception may cause Node to fail to perform memory reclamation and memory leaks. So, when an uncaughtException is fired, it’s a good idea to log the error log and then end the Node process.
process.on('uncaughtException', function(err) {
logger.log(err);
process.exit(1);
});
unhandledRejection Event
Io.js has an unhandledRejection event that listens for the rejected state of a non-captured Promise object.
var promise = new Promise(function(resolve, reject) {
reject(new Error("Broken."));
});
promise.then(function(result) {
console.log(result);
})
In the above code, the status of the promise becomes rejected and an error is thrown. However, there will be no reaction because no handler is set.
As long as you listen to the unhandledRejection event, you can solve this problem.
process.on('unhandledRejection', function (err, p) {
console.error(err.stack);
})
It should be noted that the listen function of the unhandledRejection event has two parameters, the first one is the error object, and the second one is the error object that generated the error. This can provide a lot of useful information.
var http = require('http');
http.createServer(function (req, res) {
var promise = new Promise(function(resolve, reject) {
reject(new Error("Broken."))
})
promise.info = {url: req.url}
}).listen(8080)
process.on('unhandledRejection', function (err, p) {
if (p.info && p.info.url) {
console.log('Error in URL', p.info.url)
}
console.error(err.stack)
})
The above code will output the URL requested by the user when an error occurs.
Error in URL /testurl
Error: Broken.
at /Users/mikeal/tmp/test.js:9:14
at Server.<anonymous> (/Users/mikeal/tmp/test.js:4:17)
at emitTwo (events.js:87:13)
at Server.emit (events.js:169:7)
at HTTPParser.parserOnIncoming [as onIncoming] (_http_server.js:471:12)
at HTTPParser.parserOnHeadersComplete (_http_common.js:88:23)
at Socket.socketOnData (_http_server.js:322:22)
at emitOne (events.js:77:13)
at Socket.emit (events.js:166:7)
at readableAddChunk (_stream_readable.js:145:16)
Command Line Script
The node script can be used as a command line script.
$ node foo.js
The above code executes the foo.js script file.
The first line of the foo.js file, if you add the location of the interpreter, you can call it directly as a command-line tool.
#!/usr/bin/env node
Before the call, you need to change the execution permission of the file.
$ chmod u+x foo.js
$ ./foo.js arg1 arg2 ...
Console.log Used as a command-line script for outputting content to standard output process.stdin for reading standard input child_process.exec()for executing a shell command.