Have an interview before, for front-end developers, it is necessary to know a background language.

At that time, I was asked such a few questions, although I did not write in the content of the article, you can go to study with these questions, to find the corresponding answer, is also a kind of promotion!

  • What’s the difference between a browser event loop and a Node event loop?
  • commonjstherequireThe implementation principle of?
  • The ES6importandcommonjsWhat’s the difference between require of?
  • Writing aEventEmmitclass

The following will be aimed at these problems, an article, welcome your attention.

Node

Why learn Nodejs

  • Enterprise needs
    • Experience in server-side development is a plus
    • Full stack engineer
    • Basic web development skills
      • The service side
      • The front end
      • O&m deployment related work

What is the Node

Node.js is a JavaScript runtime environment based on Chrome’S V8 engine. Node.js uses an event-driven, non-blocking I/O model, making it lightweight and efficient.

Current stable version :14.15.1 Long Term Support (LTS

Install the node

Download from the official website => One-click installation, click and click to install.

Ps: If you have changed the installation path of the Windows computer, please modify the environment variables by yourself

Of course, the latest version of Node is 14.15.1, and you can download the latest version for installation now

The installation is successful.

The preparatory work

  • Run the node program

    console.log('hello node');
    console.log('run my use:node 01-runnode');
    Copy the code

    Run: node 01 – runnode. Js

    Each js file modification takes effect only after you re-execute it. After nodemon is installed, you can monitor file changes and automatically restart the js file

    npm i -g nodemon

    Then run nodemon 01-runNode.js

  • Mode node program: debug-start Debugging

REPL(interactive interpreter)

  • Expression operation
  • Use the variable
  • Multiline expression
  • REPL command
    • CTRL + C – Exit the terminal.
    • Press CTRL + C twice – Exit Node REPL.
    • CTRL + d – Exit Node REPL.
    • Up/Down – View the history command entered
    • TAB – Lists the current commands
    • .help – Lists the commands used
    • .break – Exits a multi-line expression
    • . Clear – Exits a multi-line expression
    • . Save filename – Saves the current Node REPL session to the specified file
    • .load filename – Loads the contents of the file for the current Node REPL session.

The callback function

A direct example of Node.js asynchronous programming is callbacks.

Asynchronous programming relies on callbacks, but you can’t say that using callbacks makes the program asynchronous.

Callbacks are called when the task is complete. Node uses a large number of callbacks. All Node apis support callbacks.

For example, we can read a file while executing other commands, and when the file is read, we return the contents of the file as arguments to the callback function. This way there is no blocking or waiting for file I/O while the code executes. This greatly improves the performance of Node.js and can handle a large number of concurrent requests.

Block of code

// Blocking code
const fs = require('fs');
const data = fs.readFileSync('01-runnode.js');
console.log(data.toString());
Copy the code

Non-blocking code

const fs = require('fs');
fs.readFile('01-runnode.j'.function(err,data) {
    if(err){
        console.log(err.stack);
        return;
    }
    console.log(data.toString());
});
console.log('Proceed');
Copy the code

The first instance executes the program after the file has been read. In the second instance, we don’t have to wait for the file to be read, so we can execute the following code while the file is read, greatly improving the performance of the program.

Therefore, blocking is done sequentially, and non-blocking is not, so if we need to handle the arguments to the callback function, we need to write them inside the callback function.

Event loop

Node.js is a single-process, single-threaded application, but it supports concurrency through events and callbacks, so it performs very well.

Each API of Node.js is asynchronous and runs as a separate thread, using asynchronous function calls, and handling concurrency.

Node.js implements basically all of its event mechanisms using the Observer pattern in the design pattern.

Node.js single-threading is similar to entering a while(true) event loop until no event observer exits. Each asynchronous event generates an event observer and calls the callback function if an event occurs.

Event driver

Node.js uses an event-driven model. When the Web server receives a request, it closes it and processes it before serving the next Web request.

When the request completes, it is put back on the processing queue, and when it reaches the beginning of the queue, the result is returned to the user.

This model is very efficient and very scalable because the WebServer is always accepting requests without waiting for any read or write operations. (This is also known as non-blocking IO or event-driven IO)

In the event-driven model, a main loop is generated to listen for events and the callback function is fired when an event is detected.

This is how the whole event-driven process is implemented, and it’s very neat. Somewhat similar to the Observer pattern, an event acts as a Subject, and all handlers registered with the event act as observers.

Node.js has several built-in events. We can bind and listen for events by introducing the Events module and instantiating EventEmitter class, as shown in the following example:

Create 03 – eventEmitter. Js

// Introduce the Event module
const events = require('events');

// Create an eventEmitter object
const eventEmitter = new events.EventEmitter();

// Create an event handler
const connectHandler = function connected() {
    console.log('Connection successful');
    // Triggers the data_Received event
    eventEmitter.emit('data_received');
}

// Bind the Connection event handler
eventEmitter.on('connection', connectHandler);

// Bind the data_received event using an anonymous function
eventEmitter.on('data_received'.function() {
    console.log('Data received successfully');
})

// Triggers the Connection event
eventEmitter.emit('connection');
console.log('Program completed');

Copy the code

Perform:

Connection successful Data received successful program execution completedCopy the code

Buffer

The JavaScript language itself has only string data types, not binary data types.

But when dealing with things like TCP streams or file streams, you must use binary data. Therefore, in Node.js, we define a Buffer class, which is used to create a Buffer dedicated to binary data.

In Node.js, the Buffer class is a core library shipped with the Node kernel. Buffer brings a way for Node.js to store raw data, allowing Node.js to process binary data, and it is possible to use Buffer whenever you need to process data moved in an I/O operation in Node.js. The raw data is stored in an instance of the Buffer class. A Buffer is similar to an array of integers, but it corresponds to a chunk of raw memory outside of the V8 heap memory.

// Buffer: an array of octets that can effectively store binary data in JS
/ / create
const buf1 = Buffer.alloc(10);
console.log(buf1);
// Create by data
const buf2 = Buffer.from('hello world');
console.log(buf2);

const buf3 = Buffer.from([1.2.3]);
console.log(buf3);

/ / write
buf1.write('hello buffer');
console.log(buf1);

/ / read
console.log(buf2.toString());
console.log(buf2.toString('base64'));

/ / merge
const buf4 = Buffer.concat([buf1,buf2]);
console.log(buf4.toString());
Copy the code

The Stream (flow)

The pipe flow

Pipes provide a mechanism for an output stream to an input stream. Usually we use it to get data from one stream and pass it to another.

As shown in the picture above, we compare a file to a bucket of water, and the water is the contents of the file. We connect the two buckets with a pipe to make the water flow from one bucket to the other, thus slowly realizing the copying process of large files.

In the following example, we read the contents of one file and write the contents to another file.

const fs = require('fs');
// Create a readable stream
const readerStream = fs.createReadStream('./package.json');
// Create a writable stream
const writerStream = fs.createWriteStream('./test.txt');
// Set encoding to UTf8
readerStream.pipe(writerStream);
console.log('Execution completed');
Copy the code

Chain flow

Chaining is a mechanism for creating chains of multiple stream operations by connecting output streams to another stream. Chain flows are generally used for pipe operations

The next step is to use pipes and chaining to compress and decompress files.

const fs = require('fs');
const zlib = require('zlib');
// Compress test.txt to test.zip
fs.createReadStream('./test.txt').pipe(zlib.createGzip()).pipe(fs.createWriteStream('test.zip'));
console.log('File compression successful');
Copy the code

Module system

To make node.js files callable to each other, Node.js provides a simple module system.

Modules are the basic building blocks of a Node.js application, and there is a one-to-one correspondence between files and modules. In other words, a node.js file is a module. This file may be JavaScript code, JSON, or a compiled C/C++ extension.

CommonJS module

In Node.js, creating a module is as simple as creating main.js

const Hello = require('./hello');
hello.world();
Copy the code

Node.js provides exports and require objects. Exports are the interfaces that a module exposes, and require is used to obtain the interface of a module from an external source, i.e. the exports object of the module

Next we create the hello.js file as follows:

exports.world = function() {
   console.log('hello world');
}
Copy the code

Sometimes we just want to encapsulate an object into a module in the following format

module.exports = function() {
  // ...
}
Copy the code

Such as:

function Hello() {
    let name;
    this.setName = function(myName) {
        name = myName
    }
    this.sayHello = function() {
        console.log('hello', name); }}module.exports = Hello;
Copy the code

So we can get the object directly:

const hello = new Hello();
hello.setName('Little Horse');
hello.sayHello();
Copy the code

Exports = Hello instead of exports.world = function(){}. When the module is referenced externally, its interface object is the Hello object itself, not the original exports.

Where is the server module

As you may have noticed, we already use modules in our code. Like this:

const fs = require('fs');

fs.createReadStream(...)
Copy the code

There are many commonly used built-in modules in Nodejs, as described in the next section

The file search strategy in Node.js’s require method is as follows.

Since there are four types of modules (native module and three types of file module) in Node.js, although the require method is extremely simple, the internal loading is very complicated, and the loading priority is different. As shown in the figure below:

Load from the file module cache

Although native and file modules have different priorities, neither has precedence over loading an existing module from the file module’s cache.

Load from the native module

The priority of the native module is second only to that of the file module cache. The require method preferentially checks whether the module is in the native module list after parsing the file name. HTTP module, for example, in spite of the directory exists an HTTP/HTTP js/HTTP node/HTTP json file, the require (” HTTP “) will not be loaded from the file, but the load from the original module. Native modules also have a cache and are loaded from the cache first. If the cache has not been loaded, the native module’s loading mode is called for loading and execution.

Load from file

When a file module does not exist in the cache and is not a native module, Node.js parses the arguments passed in the require method and loads the actual file from the file system. The packing and compilation details of the loading process were described in the previous section. Here we describe the process of finding the file module in detail. There are also some details worth knowing. The require method accepts the following parameters:

  • HTTP, FS, PATH, etc., native module.
  • . / mod or.. /mod, relative to the path of the file module.
  • /pathtomodule/mod, the absolute pathto the file module.
  • Mod, a file module for a non-native module.

Common built-in modules

Fs module

Asynchronous and synchronous

Open the file

fs.open(path, flags[, mode], callback)
Copy the code

parameter

  • Path – The path of the file.

  • Flags – The behavior of file opening. Specific values are described below.

  • Mode – Sets the file mode (permission). The default file creation permission is 0666(readable and writable).

  • Callback – A callback function that takes two arguments such as callback(err, fd).

    The flags argument can be one of the following:

    Flag describe
    r Open the file in read mode. Throw an exception if the file does not exist.
    r+ Open the file in read/write mode. Throw an exception if the file does not exist.
    rs Read files synchronously.
    rs+ Read and write files synchronously.
    w Open file in write mode, create if file does not exist.
    wx Similar to ‘w’, but if the file path exists, the file fails to be written.
    w+ Open file in read/write mode, create file if it does not exist.
    wx+ Similar to ‘w+’, but if the file path exists, the file reads and writes fail.
    a Open file in append mode, create file if it does not exist.
    ax Similar to ‘a’, but if the file path exists, file appending fails.
    a+ Open file in read append mode, create file if it does not exist.
    ax+ Similar to ‘a+’, but if the file path exists, file read append fails.

    Written to the file

    fs.writeFile(filename, data[, options], callback)
    Copy the code

    If the file exists, what this method writes overwrites the old file.

    The parameters are described as follows:

    • Path – File path.
    • Data – The data to be written to the file, which can be a String or a Buffer object.
    • Options – This parameter is an object containing {encoding, mode, flag}. The default encoding is UTf8, the mode is 0666, the flag is ‘w’.
    • Callback – The callback function that contains only the error message parameter (err) and is returned when the write fails.

    Read the file

    fs.read(fd, buffer, offset, length, position, callback)
    Copy the code

    Close the file

    fs.close(fd, callback)
    Copy the code

    Capture file

    fs.ftruncate(fd, len, callback)
    Copy the code

    The parameters are described as follows:

    • Fd – The file descriptor returned by the fs.open() method.
    • Len – The length of the truncated file content.
    • Callback – A callback function that takes no arguments

    Delete the file

    fs.unlink(path, callback)
    Copy the code

    The parameters are described as follows:

    • Path – File path.
    • Callback – A callback function that takes no arguments.

    Create a directory

    fs.mkdir(path[, mode], callback)
    Copy the code
    • Path – File path.

    • Mode – Sets the directory permission. The default value is 0777.

    • Callback – A callback function that takes no arguments.

    Read the directory

    fs.readdir(path, callback)
    Copy the code

    The parameters are described as follows:

    • Path – File path.
    • Callback – callback function with two parameters, err, files, err is the error information, files is the file array list in the directory

    Delete the directory

    fs.rmdir(path, callback)
    Copy the code

    The parameters are described as follows:

    • Path – File path.
    • Callback – A callback function that takes no arguments.

How do I synchronize asynchronous code

  • promise

    const {promisify} = require('util');
    const readFile = promisify(fs.readFile);
    readFile('./01-runnode.js').then(data= >console.log(data));
    Copy the code
  • Promises API(Node 10.0 +)

    const {promises} = require('fs');
    promises.readFile('./01-runnode.js').then(data= > console.log(data));
    Copy the code
  • generator

    const fs = require('fs');
    const { promisify } = require('util');
    const readFile = promisify(fs.readFile);
    
    function* read() {
        yield readFile('./01-runnode.js');
    }
    let ge = read();
    ge.next().value.then(data= >{
        console.log(data);
    })
    Copy the code
  • async

    const fs = require('fs');
    const {promisify} = require('util');
    const readFile = promisify(fs.readFile);
    
    async function asyncReadFile() {
        let a = await readFile('./01-runnode.js');
        console.log(a.toString());
    }
    asyncReadFile();
    Copy the code

File module reference link

OS module

const os = require('os');
// Total system memory
console.log(os.totalmem());
// The amount of free memory in the operating system
console.log(os.freemem());

const mem = os.freemem() / os.totalmem() * 100;
console.log('Memory occupancy${mem}% `);
Copy the code

Using third-party modules

npm i cpu-stat -S
Copy the code
// Use a third-party module
const cpuStat = require('cpu-stat');

cpuStat.usagePercent((err,percent) = >{
    console.log(percent);
})
Copy the code

The HTTP module

Nodejs is essentially a Web server, so how do you get the HTTP server to work?

Let’s quickly familiarize ourselves with the simple but not simple HTTP server

const http = require('http');
http.createServer((req,res) = >{
    res.end('Response completed');
}).listen(3000);
Copy the code

Starting the server

Browser access :http://localhost:3000 to see the response complete

routing

The simple server above is not sufficient for our needs. For example, we need to access different routing addresses to find different pages. For example:

Visit: http://localhost:3000/index to see the home page content, visit: http://localhost:3000/about to see the content of the about me page

Visit: http://localhost:3000/user to see a json data

const http = require('http');
const fs = require('fs');
http.createServer((req,res) = >{
    const {url,method} = req;
    if(url === '/index' && method === 'GET') {// Read the home page
        fs.readFile('./index.html'.(err,data) = >{
            if(err){
                res.statusCode = 500;// An internal server error occurred
                res.end('500- Interval Serval Error! ');
            }
            res.statusCode = 200;// Set the status code
            res.setHeader('Content-Type'.'text/html'); res.end(data); })}else if(url === '/about' && method ==='GET'){
        fs.readFile('./about.html'.(err, data) = > {
            if (err) {
                res.statusCode = 500;// An internal server error occurred
                res.end('500- Interval Serval Error! ');
            }
            res.statusCode = 200;// Set the status code
            res.setHeader('Content-Type'.'text/html'); res.end(data); })}else if(url ==='/user' && method === 'GET'){
        res.statusCode = 200;// Set the status code
        res.setHeader('Content-Type'.'application/json');
        res.end(JSON.stringify([{name:"Little Horse"}]));
    }else{
        
        res.end();
    }
   
}).listen(3000);
Copy the code

The Simple version implements its own Express

Create MExpress. Js

const Application = require('./application');
function MExpress() {
    return new Application();
}
module.exports = MExpress;
Copy the code

Create application. Js

/ / demand
// 1. Implement the HTTP server
// 2. Implement the GET routing request
const http = require('http');
const url = require('url');
class Application {
    constructor() {
        this.router = [];
    }
    get(path, fn) {
        this.router.push({
            path: path,
            method: 'GET'.handle: fn
        })
    }
    listen() {
        http.createServer((req, res) = > {
            const { pathname } = url.parse(req.url);
            for (const route of this.router) {
                if (route.path === pathname) {
                   route.handle(req,res);
                   return; 
                }
                if(route.path === The '*'){
                    route.handle(req, res);
                    return; 
                }
            }
        }).listen(...arguments);
    }
}
module.exports = Application;
Copy the code

MExpress_test.js

const MExpress = require('./MExpress');
const app = MExpress();
const fs = require('fs');
const path = require('path')
app.get('/index'.(req,res) = >{
    fs.readFile('./index.html'.(err, data) = > {
        if (err) {
            res.statusCode = 500;// An internal server error occurred
            res.end('500- Interval Serval Error! ');
        }
        res.statusCode = 200;// Set the status code
        res.setHeader('Content-Type'.'text/html');
        res.end(data);
    })
})

app.get(The '*'.(req,res) = >{
    res.setHeader('Content-Type'.'image/*');
    fs.readFile(path.join(__dirname, req.url), function (err, data) {
        if (err) {
            throw err;
        }
        res.end(data);
    })
})


app.listen(3001);
Copy the code