preface

What is Node.js?

JS is a scripting language, and all scripting languages require a parser to run. The browser acts as a parser for JS written in HTML pages. For JS that needs to run independently,NodeJS is a parser.

The parser requires an engine to parse JavaScript, and Node.js uses the V8 engine,Google’s open source JavaScript engine.

So node.js is a JavaScript runtime environment based on Chrome’S V8 engine.

Node.js’ event-driven mechanism + asynchronous IO + high-performance V8 engine also makes it a great choice for writing high-performance Web services.

What can Node.js do?

It’s almost 2020, ten years after Node.js opened its source in 2009.

After so many iterations, the Node.js ecosystem has become very mature, with many excellent practices and wheels, such as Express, KOA and other Web development frameworks.

Node.js is definitely driving the development of front-end ecology, such as front-end engineering.

Instead of talking about what Node.js does, let’s talk about what I do with Node.js.

Work:

  • Made an active page generation tool based on Express

  • A monitoring system platform based on KOA + Sequelize is developed

  • Automate some scripts using Node.js to optimize repetitive work

After work:

Null – CLI is here, one – line command to improve your efficiency

5 interesting Node.js libraries that take you into the world of colorful Node.js

Customise your Toutiao with Nodejs + Docker + Github Pages

So much nonsense, what am I going to do ~

If you’re in the mood to learn about Node.js, I hope this article helps you

This article introduces you to node.js by learning about 13 basic core modules and a TodoList practice based on native Node.js!

13 basic core modules

1. Event trigger Events module

2. The local path module

3. File OS FS module

4. Global object process

5. The HTTP module

6. Uniform resource Locator URL module

Compress the zlib module

8. Stream module

9. Read the Readline module line by line

Querystring module

11. The module module

12. Buffer Module

13. DNS module of the DNS server

There are far more than 13 built-in modules in Node.js. At the beginning stage, we learned some basic core modules that are commonly used, so we can get started

If you don’t want to read the whole article, I split the 13 modules into 13 sections on the Github blog for easy reading, and the demo code for each module is also available on the blog

What does TodoList accomplish?

In order to further understand the core module of Node.js, this demo adopts the native API implementation, which is separated from some Web frameworks and libraries such as Express and KOA.

  • RESTful API practice

  • Static resource mapping and GZIP compression

  • Back-end routing Router is easy to implement

  • Node.js core module method practice

Implements a simple task management, using vue + element-UI on the front end,

├ ── ch.pdf // ch.pdf... │ ├ ──controllers // │ ├ ─ class.htm, │ ├ ── class.htm, │ ├ ─ class.htm, │ ├ ─ class.htm, │ ├ ── class.htm, │ ├ ─ class.htm, │ ├ ── class.htm, │ ├ ─ class.htm, │ ├ ── class.htm Index. The js | data. Json / / data storage │ index. The js/entry/engineeringCopy the code

The implementation does not rely on any libraries and does not install any dependencies

node index.js
Copy the code

If you want to develop or debug, nodemon is recommended. It implements hot updates and automatically restarts.

npm install -g nodemon

nodemon
#or
nodemon index.js
Copy the code

TodoList Code address

The results are as follows:

1. Event trigger Events module

Node.js uses an event-driven, non-blocking I/O model, making it lightweight and efficient.

Most of node.js’s core apis use the usual event-driven architecture, where certain types of objects (triggers) periodically fire named events to call function objects (listeners). How does Node.js implement event-driven architecture?

Events module is the core of node. js to implement event-driven, and most modules in Node inherit events class. Such as FS readStream, NET server module.

The Events module provides only one object: Events.EventEmitter. The core of EventEmitter is the encapsulation of event trigger and event listener. EventEmitter is essentially an implementation of the observer pattern.

All objects that emit events are instances of the EventEmitter class. These objects have an EventEmitter.on () function that binds one or more functions to named events. Events are usually named as hump strings, but any valid JavaScript attribute key can be used.

The EventEmitter object uses eventEmitter.emit() to emit events. When an EventEmitter object emits an event, all functions bound to that event are called simultaneously. Any value returned by the called listener will be ignored and discarded.

Let’s learn about the Events module with a few simple examples

1. Basic examples

Register an Application instance, inherit EventEmitter, listen for events through the inherited EventEmitter.on() function, and EventEmitter.emit() fires events

const EventEmitter = require('events')
/** * Expose `Application` class. * Inherits from `EventEmitter.prototype`. */
class Application extends EventEmitter {}
const app = new Application()
// Listen for the Hello event
app.on('hello', data => {
  console.log(data) // hello nodeJs
})
// Triggers the Hello event
app.emit('hello'.'hello nodeJs')
Copy the code

2. Multiple event listeners and this point

When multiple event listeners are bound, the event listeners are executed in the order they were registered.

When the listener function is called, this keyword is pointed to the EventEmitter instance to which the listener is bound. You can also use ES6’s arrow function as a listener, but the this keyword does not point to an EventEmitter instance.

const EventEmitter = require('events')

class Person extends EventEmitter {
  constructor() {
    super()}}const mrNull = new Person()
// Listen for play events
mrNull.on('play'.function(data) {
  console.log(this)
  // Person {
  // _events:
  // [Object: null prototype] { play: [[Function], [Function]] },
  // _eventsCount: 1,
  // _maxListeners: undefined
  // }
  console.log(`play`)})// Listen for play events
mrNull.on('play', data => {
  console.log(this) / / {}
  console.log(`play again`)})// Triggers the play event
mrNull.emit('play'.'hello nodeJs')
Copy the code

3. Synchronous VS Asynchronous

EventEmitter calls all listeners synchronously in the order they are registered.

const EventEmitter = require('events')

class Person extends EventEmitter {
  constructor() {
    super()}}const mrNull = new Person()
mrNull.on('play'.function(data) {
  console.log(data)
})

mrNull.emit('play'.'hello nodeJs')

console.log(`hello MrNull`)

// hello nodeJs
// hello MrNull
Copy the code

The listener functions can use the setImmediate() and process.nexttick () methods to switch to an asynchronous mode of operation

const developer = new Person()
developer.on('dev'.function(data) {
  setImmediate((a)= > {
    console.log(data)
  })
})
developer.on('dev'.function(data) {
  process.nextTick((a)= > {
    console.log(data)
  })
})
developer.emit('dev'.'hello nodeJs')

console.log(`hello developer`)

// hello developer
// hello nodeJs
// hello nodeJs
Copy the code

4. Event listeners that are invoked only once

Use EventEmitter.once () to register listeners that can be called up to once. When the event is raised, the listener is logged out and then called.

const EventEmitter = require('events')

class Person extends EventEmitter {
  constructor() {
    super()}}const mrNull = new Person()
mrNull.once('play', () = > {console.log('play ! ')
})

mrNull.emit('play')
mrNull.emit('play')

// play ! You only print it once
Copy the code

5. Event triggering sequence

If the event is triggered before it is registered, it will not be triggered!!

const EventEmitter = require('events')

class Person extends EventEmitter {
  constructor() {
    super()}}const mrNull = new Person()

mrNull.emit('play')

mrNull.on('play', () = > {console.log('play ! ')})// No output
Copy the code

6. Remove the event listener

const EventEmitter = require('events')

class Person extends EventEmitter {
  constructor() {
    super()}}const mrNull = new Person()

function play() {
  console.log('play ! ')
}
mrNull.on('play', play)

mrNull.emit('play')

// mrNull.off("play", play); New in V10.0.0, an alias for Emitter.Removelistener ().
// or
mrNull.removeListener('play', play)

mrNull.emit('play')

// play ! No longer triggers after removal
Copy the code

2. The local path module

Node.js provides the path module for handling file paths and directory paths. Different operating systems have different performance!

1. Obtain the directory name of the path

const path = require('path')

path.dirname('/path/example/index.js') // /path/example
Copy the code

2. Obtain the extension name of the path

const path = require('path')

path.extname('/path/example/index.js') // .js
Copy the code

3. Whether the path is an absolute path

const path = require('path')

path.isAbsolute('/path/example/index.js') // true

path.isAbsolute('. ') // false
Copy the code

4. Splice the path fragments

path.join('/path'.'example'.'./index.js') // /path/example/index.js
Copy the code

5. Resolve the sequence of paths or path fragments into absolute paths.

path.resolve('/foo/bar'.'./baz')
Return: '/foo/bar/baz'

path.resolve('/foo/bar'.'/tmp/file/')
// Return: '/ TMP /file'

path.resolve('wwwroot'.'static_files/png/'.'.. /gif/image.gif')
// If the current working directory is /home/myself/node,
/ / returns'/home/myself/node/below/static_files/GIF image. GIF '
Copy the code

6. Normalize the path

path.normalize('/path///example/index.js') // /path/example/index.js
Copy the code

7. Resolve the path

path.parse('/path/example/index.js')

/* { root: '/', dir: '/path/example', base: 'index.js', ext: '.js', name: 'index' } */
Copy the code

8. Serialize the path

path.format({
  root: '/'.dir: '/path/example'.base: 'index.js'.ext: '.js'.name: 'index'
}) // /path/example/index.js
Copy the code

9. Obtain the relative path from to to

path.relative('/path/example/index.js'.'/path') / /.. /..
Copy the code

3. File OS FS module

Nodejs provides the FS module that allows you to add, delete, modify, and check files in some scenarios.

Let’s look at a few of the most frequently used apis

1. Read the file

const fs = require('fs')
const fs = require('fs')

// Read asynchronously
fs.readFile('./index.txt'.'utf8', (err, data) => {
  console.log(data) // Hello Nodejs
})

// Read synchronously
const data = fs.readFileSync('./index.txt'.'utf8')

console.log(data) // Hello Nodejs

// Create a read stream
const stream = fs.createReadStream('./index.txt'.'utf8')

Fs.createreadstream listens for events EventEmitter.on (). Fs.createreadstream listens for events eventEmitter
stream.on('data', data => {
  console.log(data) // Hello Nodejs
})
Copy the code

2. Write/modify files

If the file does not exist, the system writes the file. If the file does exist, the system overwrites the file.

const fs = require('fs')
// Write asynchronously
fs.writeFile('./write.txt'.'Hello Nodejs'.'utf8', err => {
  if (err) throw err
})
// Write synchronously
fs.writeFileSync('./writeSync.txt'.'Hello Nodejs')
// The file stream is written
const ws = fs.createWriteStream('./writeStream.txt'.'utf8')
ws.write('Hello Nodejs')
ws.end()
Copy the code

3. Delete files or folders

  • Delete the file
// Delete files asynchronously
fs.unlink('./delete.txt', err => {
  if (err) throw err
})

// Delete files synchronously
fs.unlinkSync('./deleteSync.txt')
Copy the code
  • Deleting a folder
// Delete folders asynchronously
fs.rmdir('./rmdir', err => {
  if (err) throw err
})

// Delete folders synchronously
fs.rmdirSync('./rmdirSync')
Copy the code

4. Create a folder

// Create folders asynchronously
fs.mkdir('./mkdir', err => {
  if (err) throw err
})

// Create folders synchronously
fs.mkdirSync('./mkdirSync')
Copy the code

5. Rename files/folders

const fs = require('fs')

// Rename files asynchronously
fs.rename('./rename.txt'.'./rename-r.txt', err => {
  if (err) throw err
})

// Rename the folder synchronously
fs.renameSync('./renameSync'.'./renameSync-r')
Copy the code

6. Copy files/folders

const fs = require('fs')

// Copy files asynchronously
fs.copyFile('./copy.txt'.'./copy-c.txt', (err, copyFiles) => {
  if (err) throw err
})

// Copy folders synchronously
fs.copyFileSync('./null'.'null-c')
Copy the code

7. Folder status – File/folder

const fs = require('fs')

// Obtain the file status asynchronously
fs.stat('./dir', (err, stats) => {
  if (err) throw err
  // Whether it is a file type
  console.log(stats.isFile()) // false
  // Whether it is a folder type
  console.log(stats.isDirectory()) // true
})

// Obtain the file status synchronously
const stats = fs.statSync('./stats.txt')

// Whether it is a file type
console.log(stats.isFile()) // true
// Whether it is a folder type
console.log(stats.isDirectory()) // false
Copy the code

In some complex scenarios, the FS module requires a lot of judgment and processing, and I recommend it herefs-extraIt extends some methods on the basis of FS to make some complex operations easier!

4. Global object process

The Process object is a Global object that you can use anywhere without requiring. Process is an instance of EventEmitter, so there are listeners for related events. Using the Process object makes it easy to handle process-related operations.

Process Common attributes

Process command line argument: process.argv

Process. argv is a set of arguments for the currently executing process. The first argument is node, the second argument is the name of the.js file that is currently executing, followed by a list of arguments that are set at execution time.

node index.js --tips="hello nodejs"

/* [ '/usr/local/bin/node', 'xxx/process/index.js', '--tips=hello nodejs' ] */
Copy the code

An array of command line arguments for Node: process.execArgv

The process.execArgv property returns an array of Node’s command-line arguments.

node --harmony index.js --version

console.log(process.execArgv);  // [ '--harmony' ]

console.log(process.argv);

/* [ '/usr/local/bin/node', 'xxx/process/index.js', '--version' ] */

Copy the code

Version of Node at compile time: process.version

The process.version attribute returns the version number of the Node at compile time, which is stored in Node’s built-in variable NODE_VERSION.

console.log(process.version) / / v10.15.3
Copy the code

PID of the current process process. PID

The process.pid attribute returns the PID of the current process.

console.log('process PID: %d', process.pid)

//process PID: 10086
Copy the code

Process Common methods

Current working directory process.cwd()

The process.cwd() method returns the process’s current working directory

console.log(process.cwd()) // /Users/null/nodejs/process
Copy the code

To terminate the current process: process.exit([code])

The process.exit() method terminates the current process. This method receives an optional exit status parameter code, and returns a success status code of 0 if not passed in.

process.on('exit'.function(code) {
  console.log('Process exit code is :%d', code) // The process exit code is 886
})

process.exit(886)
Copy the code

Nodejs microtask: process.nexttick ()

The process.nexttick () method is used to delay the execution of the callback function. The nextTick method delays the callback function in the callback to the next loop in the event loop. It is much more efficient than setTimeout(fn, 0). This method can call our callback function before any I/O.

console.log('start')
process.nextTick((a)= > {
  console.log('nextTick cb')})console.log('end')

// start
// end
// nextTick cb
Copy the code

Process Standard flow object

There are three standard standby stream operations in Process. Unlike other STREAMS flow operations, stream operations in Process are synchronous writes and blocked.

Standard error stream: process.stderr

Process. stderr is a Writable Stream that points to the standard error Stream. Console. error is implemented through process.stderr.

Standard input stream: process.stdin

Process. stdin is a Readable Stream that points to the standard input Stream.

process.stdin.setEncoding('utf8')

process.stdin.on('readable', () = > {let chunk
  // Use a loop to make sure we read all available data.
  while((chunk = process.stdin.read()) ! = =null) {
    if (chunk === '\n') {
      process.stdin.emit('end')
      return
    }
    process.stdout.write('Received data:${chunk}`)
  }
})

process.stdin.on('end', () => {
  process.stdout.write('End listening')})Copy the code

Standard output stream: process.stdout

Process. stdout is a Writable Stream that points to the standard output Stream. Console. log is implemented through process.stdout

console.log = function(d) {
  process.stdout.write(d + '\n')}console.log('Hello Nodejs') // Hello Nodejs
Copy the code

5. The HTTP module

HTTP module is a very important core module in Node.js. With the HTTP module, you can create an HTTP server using its http.createServer method and an HTTP client using its http.request method. (Aside from this article),Node encapsulates HTTP protocol and related apis at a relatively low level. It can only process flows and messages. For message processing, it can only parse into packet headers and packet style, but it does not parse the actual packet header and packet style content. This not only solves some of the more difficult features of HTTP, but also supports more HTTP applications.

HTTP. IncomingMessage object

The IncomingMessage object is created by http.Server or http.ClientRequest, This is passed as the first argument to http.Server’s ‘request’ event and http.ClientRequest’s ‘response’ event, respectively.

It can also be used to access the status of the response, headers, data, and so on. The IncomingMessage object implements the Readable Stream interface, along with several events, methods, and properties.

This is slightly different in http.Server or HTTP. ClientRequest.

Http. createServer([requestListener]) Creates an HTTP server

To implement the HTTP Server function, create a Server object http.server using the http.createserver method.

This method receives an optional parameter requestListener, which is a function that listens for HTTP.Server’s request event. If not, it needs to be added separately in the request event of the HTTP. Server object.

var http = require('http')

// Create the server object and add the request event listener
var server = http.createServer(function(req, res) {
  res.writeHeader(200, { 'Content-Type': 'text/plain' })
  res.end('Hello Nodejs')})// Create a server object and add an event event listener through the request event of the server object
var server = new http.Server()
server.on('request'.function(req, res) {
  res.writeHeader(200, { 'Content-Type': 'text/plain' })
  res.end('Hello Nodejs')})Copy the code

Http. Server Server object

The HTTP.Server object is an EventEmitter that emits: Request, Connection, close, checkContinue, connect, Upgrade, clientError events.

Function (request, response) {}; Request is an HTTP.IncomingMessage instance, and Response is an HTTP.ServerResponse instance.

There are also methods in the http.Server object that allow HTTP.Server to receive incoming client connections by calling server.listen.

http.ServerResponse

The http.ServerResponse object is used to process client requests in response.

ServerResponse is an object created inside the HTTP Server (http.server) and passed as the second argument to the listener for the ‘request’ event.

ServerResponse implements the Writable Stream interface, whose response to the client is essentially an operation on the Writable Stream. It is also an EventEmitter, which includes the close and Finish events.

Create an http.server

Create http.server using the http.createserver () method. In order to process client requests, the Server needs to listen for ‘request’ events from the client.

The callback to the ‘request’ event returns an instance of http.incomingMessage and an http.serverResponse.

const http = require('http')
/** * @param {Object} req is an HTTP.IncomingMessag instance * @param {Object} res is an HTTP.ServerResponse instance */
const server = http.createServer((req, res) = > {
  console.log(req.headers)
  res.end(`Hello Nodejs`)
})

server.listen(3000)
Copy the code

The http.ServerResponse instance is a writable stream, so you can connect a file stream to the RES response stream. The following example is to circulate an image to an HTTP response:

const http = require('http')
/** * @param {Object} req is an HTTP.IncomingMessag instance * @param {Object} res is an HTTP.ServerResponse instance */
const server = http.createServer((req, res) = > {
  res.writeHead(200, { 'Content-Type': 'image/jpg' })
  const r = require('fs').createReadStream('./kobe.jpg')
  r.pipe(res)
})

server.listen(3000)
Copy the code

6. Uniform resource Locator URL module

Node.js provides the URL module for processing and parsing urls.

1. What properties do URL objects have?

const { URL } = require("url");

const myURL = new URL("https://github.com/webfansplz#hello");
console.log(myURL);
{
  href: 'https://github.com/webfansplz#hello'.// Serialized URL
  origin: 'https://github.com'.// The origin of the serialized URL
  protocol: 'https:'.// URL protocol
  username: ' '.// The user name of the URL
  password: ' '.// The password for the URL
  host: 'github.com'.// URL of the host
  hostname: 'github.com'.// The hostname of the URL
  port: ' '.// The port of the URL
  pathname: '/webfansplz'.// The path of the URL
  search: ' '.// Serialized query parameters for the URL
  searchParams: URLSearchParams {}, // URL Query parameter URLSearchParams object
  hash: '#hello'  // A fragment of the URL
}
Copy the code

The URL object properties are writable except for Origin and searchParams, which are read-only.

2. Serialize the URL

const { URL } = require('url')

const myURL = new URL('https://github.com/webfansplz#hello')

console.log(myURL.href) // https://github.com/webfansplz#hello

console.log(myURL.toString()) // https://github.com/webfansplz#hello

console.log(myURL.toJSON()) // https://github.com/webfansplz#hello
Copy the code

Compress the zlib module

In order to reduce data transmission and speed up transmission, compression is often carried out in stream transmission.

HTTP streams are compressed on the server to speed up site response, and then decompressed on the client after receiving the data.

The Zlib module in Node.js provides stream compression and uncompression. The Zlib module provides bindings to the Gzip/Gunzip, Deflate/ InflateRaw, and DeflateRaw classes, which can compress and uninflate both readable and writable streams.

About GZIP and Deflate

Deflate (RFC1951) is a compression algorithm encoded using LZ77 and haverman. Gzip (RFC1952) A compressed format that is a simple encapsulation of Deflate, gZIP = GZIP header (10 bytes) + the actual content of the deflate encoded + gZIP tail (8 bytes). Gzip is a common compression algorithm used in HTTP transfers. HTTP streams that are compressed using GZIP are identified in the HTTP header using Content-Encoding: gzip.

In the HTTP Request Header, accept-encoding is sent by the browser to the server, specifying the decompression type supported by the browser

Accept-Encoding: gzip, deflate, br
Copy the code

Content-encoding in the HTTP Response Header is what the server tells the browser which compression type is being used

Content-Encoding: gzip
Copy the code

For those of you who know something about Web performance optimization, we believe that you are not unfamiliar with gZIP, so we will learn about the Zlib module through gzip.

1. Compress/decompress files

File compression

const zlib = require('zlib')
const fs = require('fs')
const gzip = zlib.createGzip()
const inp = fs.createReadStream('zlib.txt')
const out = fs.createWriteStream('zlib.txt.gz')
inp.pipe(gzip).pipe(out)
Copy the code

File decompression

const zlib = require('zlib')
const fs = require('fs')
const gunzip = zlib.createGunzip()
const inp = fs.createReadStream('./un-zlib.txt.gz')
const out = fs.createWriteStream('un-zlib.txt')
inp.pipe(gunzip).pipe(out)
Copy the code

2. Compress gZIP files on the server

const fs = require('fs')
const http = require('http')
const zlib = require('zlib')
const filepath = './index.html'

const server = http.createServer((req, res) = > {
  const acceptEncoding = req.headers['accept-encoding']
  if (acceptEncoding.includes('gzip')) {
    const gzip = zlib.createGzip()
    res.writeHead(200, {
      'Content-Encoding': 'gzip'
    })
    fs.createReadStream(filepath)
      .pipe(gzip)
      .pipe(res)
  } else {
    fs.createReadStream(filepath).pipe(res)
  }
})

server.listen(4396)
Copy the code

8. Stream module

Stream is an abstract interface in Node.js that processes streaming data. The Stream module is used to build objects that implement a stream interface.

Node.js provides a variety of stream objects. For example, HTTP server requests and process.stdout are both instances of streams.

Streams can be readable, writable, or readable and writable. All streams are instances of EventEmitter.

Although it is important to understand how streams work, the Stream module is primarily used by developers to create new types of stream instances. For developers who primarily consume stream objects, there is very little need to use the Stream module directly.

The stream type

There are four basic stream types in Node.js:

  • Writable – A stream to which data can be written (for example, fs.createWritestream ()).

  • Readable – a stream that can read data (for example, fs.createreadStream ()).

  • Duplex – STREAMS that are both readable and writable (for example, net.socket).

  • Transform – A Duplex stream that can modify or Transform data during read/write (for example, zlib.createDeflate()).

Apis for consuming streams

const http = require('http')

const server = http.createServer((req, res) = > {
  // Req is an HTTP.IncomingMessage instance, which is a readable stream.
  // Res is an HTTP.ServerResponse instance that is a writable stream.

  let body = ' '
  // Receive data as utf8 string,
  // If no character encoding is set, a Buffer object is received.
  req.setEncoding('utf8')

  // If a listener is added, the readable stream fires the 'data' event.
  req.on('data', chunk => {
    body += chunk
  })

  // The 'end' event indicates that the entire request body has been received.
  req.on('end', () = > {try {
      const data = JSON.parse(body)
      // Give the user a response message.
      res.write(typeof data)
      res.end()
    } catch (er) {
      // Json parsing failed.
      res.statusCode = 400
      return res.end(` error:${er.message}`)
    }
  })
})

server.listen(1337)

// curl localhost:1337 -d "{}"
// object
// curl localhost:1337 -d "\"foo\""
// string
// curl localhost:1337 -d "not json"
Unexpected token o in JSON at position 1
Copy the code

The Readable stream uses the EventEmitter API to notify the application when data can be read from the stream (such as the REQ Data event in the example). There are many ways to read data from a stream.

Writable streams (such as res in the example) expose methods such as write() and end() for writing data to the stream.

Both writable and readable streams use the EventEmitter API in several ways to communicate the current state of the stream. Duplex and Transform streams are both writable and readable.

For applications that only need to write data to or consume data from a stream, there is no need to directly implement the interface to the stream, and there is usually no need to call require(‘stream’).

For most nodeJS developers, the stream module is not used directly, but it is important to understand how streams work.

9. Read the Readline module line by line

The readline module is a line-by-line reading module of the content of a stream, referred to by require(‘readline’). You can use the readline module to read stdin, to read the stream line by line, and to perform some interaction with the user on the console.

const readline = require('readline')

const rl = readline.createInterface({
  // Readable stream to listen for
  input: process.stdin,
  // Readline by line (Readline) the writable stream to which the data is to be written
  output: process.stdout
})

rl.question('What do you think of null-CLI? ', answer => {
  console.log('Thank you for your valuable comments:${answer}`)
  rl.close()
})
Copy the code

Many interesting CLI tools are based on readline, you can also try it

Querystring module

The querystring module is one of the tool modules in node.js that processes the querystring in the URL, that is, the: querystring part. Query string refers to: URL string, from the question mark “?” (Not included?) The part that starts at the anchor “#” or ends at the URL string (if # exists, ends at #, if not) is called the query string. The QueryString module parses URL query strings into objects or serializes objects into query strings.

1. Serialize the object as a query string

querystring.stringify(obj[, sep][, eq][, options])

const querystring = require('querystring')

const obj = {
  url: 'github.com/webfansplz'.name: 'null'
}

console.log(querystring.stringify(obj)) // url=github.com%2Fwebfansplz&name=null
Copy the code

2. The query string is parsed into an object

const querystring = require('querystring')

const o = querystring.parse(`url=github.com%2Fwebfansplz&name=null`)

console.log(o.url) // github.com/webfansplz
Copy the code

3. Encode the parameters in the query string

The querystring.escape method encodes the querystring, which may be used when using the querystring.stringify method.

const str = querystring.escape(`url=github.com%2Fwebfansplz&name=null`)

console.log(str) // url%3Dgithub.com%252Fwebfansplz%26name%3Dnull
Copy the code

4. Decode the parameters in the query string

The queryString. unescape method is the inverse of queryString. escape and may be used when using the QueryString. parse method.

const str = querystring.escape(`url=github.com%2Fwebfansplz&name=null`)

console.log(querystring.parse(str)) / / {' url=github.com % 2 fwebfansplz & name = null ':'} ✖ ️

console.log(querystring.parse(querystring.unescape(str))) // { url: 'github.com/webfansplz', name: 'null' }
Copy the code

11. The module module

Node.js implements a simple module loading system. In Node.js, there is a one-to-one relationship between files and modules, which can be understood as a file is a module. The implementation of its module system mainly depends on the global object Module, which implements the mechanism of exports(export), require()(load) and so on.

1. Load the module

A file in Node.js is a module. For example, load circle.js from the same directory in index.js:

// circle.js
const PI = Math.PI

exports.area = r= > PI * r * r

exports.circumference = r= > 2 * PI * r
Copy the code
// index.js
const circle = require('./circle.js')

console.log(The area of a circle with radius 4 is${circle.area(4)}`) // The area of a circle with a radius of 4 is 50.26548245743669
Copy the code

There are two methods exported by exports in circle.js: area() and circumference, which can be called in other modules.

Exports and the module exports

Exports is a simple reference to module.exports. Use module.exports if you need to export a module as a function (e.g., a constructor), or if you want to export a complete export object instead of exporting it as a property.

// square.js

module.exports = width= > {
  return {
    area: (a)= > width * width
  }
}
Copy the code
// index.js

const square = require('./square.js')
const mySquare = square(2)
console.log(`The area of my square is ${mySquare.area()}`) // The area of my square is 4
Copy the code

2. Access the main module

When node.js runs a file directly, the require.main property is set to the Module itself. In this case, we can use this property to determine whether the module is being run directly:

require.main === module
Copy the code

For example, for index.js in the above example, the node index.js face value is true, but for require(‘./index’), the value is false.

Module provides a filename attribute whose value is usually equal to __filename. Therefore, the entry point for the current program can be obtained by require.main.filename.

console.log(require.main.filename === __filename) // true
Copy the code

3. Resolve the module path

Use the require.resolve() function to get the exact file name of the module that require loaded. This operation only returns the resolved file name, not the module loaded.

console.log(require.resolve('./square.js')) // /Users/null/meet-nodejs/module/square.js
Copy the code

Work process of require.resolve:

require(X) from module at path Y
1. If X is a core module,
   a. return the core module
   b. STOP
2. If X begins with '/' or '/' or '.. / '
   a. LOAD_AS_FILE(Y + X)
   b. LOAD_AS_DIRECTORY(Y + X)
3. LOAD_NODE_MODULES(X, dirname(Y))
4. THROW "not found"

LOAD_AS_FILE(X)
1. If X is a file, load X as JavaScript text.  STOP
2. If X.js is a file, load X.js as JavaScript text.  STOP
3. If X.json is a file, parse X.json to a JavaScript Object.  STOP
4. If X.node is a file, load X.node as binary addon.  STOP

LOAD_AS_DIRECTORY(X)
1. If X/package.json is a file,
   a. Parse X/package.json, and look for "main" field.
   b. let M = X + (json main field)
   c. LOAD_AS_FILE(M)
2. If X/index.js is a file, load X/index.js as JavaScript text.  STOP
3. If X/index.json is a file, parse X/index.json to a JavaScript object. STOP
4. If X/index.node is a file, load X/index.node as binary addon.  STOP

LOAD_NODE_MODULES(X, START)
1. let DIRS=NODE_MODULES_PATHS(START)
2. for each DIR in DIRS:
   a. LOAD_AS_FILE(DIR/X)
   b. LOAD_AS_DIRECTORY(DIR/X)

NODE_MODULES_PATHS(START)
1. let PARTS = path split(START)
2. let I = count of PARTS - 1
3. let DIRS = []
4. while I >= 0,
   a. if PARTS[I] = "node_modules" CONTINUE
   c. DIR = path join(PARTS[0. I] +"node_modules")
   b. DIRS = DIRS + DIR
   c. let I = I - 1
5. return DIRS
Copy the code

4. Module cache

Modules are cached in the require.cache object after the first load, and removing the key-value pairs from this object will cause require to reload the deleted modules the next time.

Multiple calls to require(‘index’) do not necessarily result in multiple executions of the code in the module. This is an important feature that allows you to return partially completed objects; This way, pass-through dependencies can be loaded, even though they may lead to circular dependencies.

If you want a module to be executed multiple times, you should print a function and then call that function.

Considerations for module caching

Module is cached based on its parsed file name. Depending on the location of the call, it may resolve to a different file (for example, if it needs to be loaded from the node_modules folder). So, when parsed to another file, there is no guarantee that require(‘index’) will always return the exact same object.

In addition, in a case-insensitive file system or system, different filenames may resolve to the same file, but the cache will still treat them as different modules and load the file multiple times. For example, require(‘./index’) and require(‘./index’) return two different objects, whether or not ‘./index’ and ‘./index’ are the same file.

5. Circular dependency

When require() is called in a loop, the module may not be executed on return.

// a.js
console.log('a starting')
exports.done = false
const b = require('./b.js')
console.log('in a, b.done = %j', b.done)
exports.done = true
console.log('a done')
Copy the code
// b.js
console.log('b starting')
exports.done = false
const a = require('./a.js')
console.log('in b, a.done = %j', a.done)
exports.done = true
console.log('b done')
Copy the code
// main.js
console.log('main starting')
const a = require('./a.js')
const b = require('./b.js')
console.log('in main, a.done=%j, b.done=%j', a.done, b.done)
Copy the code

First main.js loads a.js, and then A.js loads B.JS. At this point, B.js will try to load A.JS again.

To prevent an infinite loop, A. js will return an unfinished copy to B. JS. B. js then stops loading and returns its exports to the a.js module.

Main.js loads the a.js and B.js files. The output is as follows:

$ node main.js
main starting
a starting
b starting
in b, a.done = false
b done
in a, b.done = true
a done
in main, a.done=true, b.done=true
Copy the code

6. File module

When loading a file module, if the file name search is not found. Then Node.js will try to add.js and.json extensions and try again. If it is still not found, the. Node extension is added to try again.

For.js files, they are parsed into JavaScript text files; Whereas.json will parse into a JOSN file; .node attempts to parse into a compiled plug-in file, which is loaded by dlopen.

Path analysis

Absolute path when the loaded file module is prefixed with ‘/’. For example, require(‘/home/null/index.js’) loads the /home/null/index.js file.

The ‘./’ prefix indicates a relative path. For example, in index.js require(‘./circle’) reference, circle.js must be in the same directory to load successfully.

When there is no ‘/’ or ‘./’ prefix, the referenced module must be either a “core module” or a module in node_modules.

If the loaded module does not exist, require() throws an error with the code attribute ‘MODULE_NOT_FOUND’.

7. __dirname

The directory name of the current module. Same as path.dirname() for __filename.

console.log(__dirname) // /Users/null/meet-nodejs/module

console.log(require('path').dirname(__filename)) // /Users/null/meet-nodejs/module

console.log(__dirname === require('path').dirname(__filename)) // true
Copy the code

8. The module object

Module represents a reference to the current module within each module. Module. exports can in turn be referenced through the global object exports. A module is not a global object, but rather an internal module object.

module.children

All module objects introduced by this module

module.exports

Module. exports is created through the module system. Sometimes it doesn’t work the way we want it to, and sometimes we want modules to be instances of classes. Therefore, we would assign the exported object to module.exports, but the objects needed for the export would be assigned a bound local export variable, which might not be what we want.

// a.js

const EventEmitter = require('events')

module.exports = new EventEmitter()

// Do some work, and after some time emit
// the 'ready' event from the module itself.
setTimeout((a)= > {
  module.exports.emit('ready')},1000)
Copy the code
const a = require('./a')
a.on('ready', () = > {console.log('module a is ready')})Copy the code

Note that the export value assigned to module.exports must be available immediately; it will not execute properly when using callbacks.

Exports alias

Exports can be used as a reference to module.exports. As with any variable, if a new value is assigned to it, its old value is invalidated:

function require(.) {
  // ...
  ((module, exports) = > {
    // Your module code here
    exports = some_func;        // re-assigns exports, exports is no longer
                                // a shortcut, and nothing is exported.
    module.exports = some_func; // makes your module export 0}) (module.module.exports);
  return module;
}

Copy the code
  • Module. filename – the complete filename after the module is parsed

  • Module.id – An identifier used to distinguish modules, usually a fully resolved file name.

  • Module. loaded – Indicates whether the module is loaded successfully

  • Module. parent – The parent module, that is, the module that introduced the module

  • module.require(id)

  • Module.require provides functionality similar to require() to load a module from the original module

12. Buffer Module

Before TypedArray was introduced, the JavaScript language had no mechanism for reading or manipulating binary data streams. The Buffer class was introduced as part of the Node.js API to interact with octets in TCP streams, file system operations, and other contexts.

Creating a buffer

console.log(Buffer.from([1.2.3.4.5])) // <Buffer 01 02 03 04 05>

console.log(Buffer.from(new ArrayBuffer(8))) // <Buffer 00 00 00 00 00 00 00 00>

console.log(Buffer.from('Hello world')) // <Buffer 48 65 6c 6c 6f 20 77 6f 72 6c 64>
Copy the code

Buffer and character encoding

A character encoding can be specified when string data is stored in or extracted from a Buffer instance.

// Convert the buffer to a string in UTF-8 format

const buffer = Buffer.from('Hello world')

console.log(buffer.toString()) // Hello world
Copy the code
// Convert the buffer data to base64 format strings

const buffer = Buffer.from('Hello world')

console.log(buffer.toString('base64')) // SGVsbG8gd29ybGQ=
Copy the code
// Convert the base64 encoded string to UTF-8 encoding

const buffer = Buffer.from('Hello world')

const base64Str = buffer.toString('base64')

const buf = Buffer.from(base64Str, 'base64')

console.log(buf.toString('utf8')) // Hello world
Copy the code

13. DNS module of the DNS server

Domain Name System (DNS) : DNS runs on top of UDP and uses port 53. DNS is a distributed database that maps domain names and IP addresses on the Internet, enabling users to more easily access the Internet without having to remember IP numbers that can be read directly by machines. Simply put, it is to resolve the domain name (url) into the corresponding IP address. The DNS module of Node.js provides DNS resolution function. When using the net.connect(80, ‘github.com/webfansplz’) method in the DNS module or http.get({host: ‘github.com/webfansplz’}), the dns.lookup method in the DNS module is used to resolve the domain name.

Two domain name resolution modes of the DNS module

1. Use the underlying DNS service of the operating system for resolution

If you use the underlying DNS service of the operating system to resolve domain names, you do not need to connect to the network and only use the built-in DNS resolution function of the system. This is done by the dns.lookup() method.

Dns.lookup (hostname[, options], callback) : resolve A domain name (e.g., ‘www.baidu.com’) to the first found A record (IPv4) or AAAA record (IPv6)

Hostname Indicates the domain name to be resolved.

Options can be an object or an integer. If the options parameter is not provided, both IP V4 and V6 addresses are acceptable. If options is an integer, it must be 4 or 6. If options is an object, it contains the following two optional parameters:

  • Family: The IP version is optional. If provided, it must be 4 or 6. If not, IP V4 and V6 addresses are acceptable

  • Hints: Optional. If provided, it can be one or more getAddrInfo flags. If not, no flags will be passed to getAddrInfo.

(err, address, family). When an Error occurs, the parameter err is an Error object. The address parameter indicates the IP V4 or V6 address. The family parameter is 4 or 6, indicating the address protocol version.

const dns = require('dns')

dns.lookup(`www.github.com`, (err, address, family) => {
  if (err) throw err
  console.log(Address: %j Address family: IPv%s', address, family) Address: "13.229.188.59" Address family: IPv4
})
Copy the code

2. Connect to the DNS server to resolve the domain name

In the DNS module, except the dns.lookup() method, the DNS server is used for domain name resolution, which requires connecting to the network.

Dns.resolve (hostname[, rrtype], callback) : Resolve a domain name (such as ‘www.baidu.com’) into an array of the type specified by RRType

Hostname Indicates the domain name to be resolved.

Rrtype has the following values available:

rrtype Records contain Type of result Quick way
‘A’ IPv4 address (default) string dns.resolve4()
‘AAAA’ IPv6 address string dns.resolve6()
‘ANY’ Any records Object dns.resolveAny()
‘CNAME’ Specification name record string dns.resolveCname()
‘MX’ Mail exchange record Object dns.resolveMx()
‘NAPTR’ Name permission pointer record Object dns.resolveNaptr()
‘NS’ Name server record string dns.resolveNs()
‘PTR’ Pointer to the record string dns.resolvePtr()
‘SOA’ Start authorization Record Object dns.resolveSoa()
‘SRV’ Service record Object dns.resolveSrv()
‘TXT’ Text record string[] dns.resolveTxt()

Callback callback with parameters including (err, addresses). When an Error occurs, the parameter err is an Error object. Addresses will return different values depending on the type of record.

const dns = require('dns')

dns.resolve('www.baidu.com'.'A', (err, addresses) => {
  if (err) throw err
  console.log(` IP address:The ${JSON.stringify(addresses)}`) // IP address: ["163.177.151.110","163.177.151.109"]
})

// or

dns.resolve4('www.baidu.com', (err, addresses) => {
  if (err) throw err
  console.log(` IP address:The ${JSON.stringify(addresses)}`) // IP address: ["163.177.151.110","163.177.151.109"]
})
Copy the code

Reverse DNS Query

Resolves an IPv4 or IPv6 address into an array of host names.

Resolve the incoming address and port to the domain name and service using the getNameInfo method

dns.reverse(ip, callback)

IP Indicates the IP address to be reversely resolved.

The callback function contains (err, domains) parameters. When an Error occurs, the parameter err is an Error object. Domains Resolved domain array.

dns.reverse('8.8.8.8', (err, domains) => {
  if (err) throw err
  console.log(domains) // [ 'dns.google' ]
})
Copy the code

dns.lookupService(address, port, callback)

Address Indicates the IP address string to be parsed.

Port Indicates the port number to be parsed.

Callback is a callback function with parameters (err, hostname, service). When an Error occurs, the parameter err is an Error object.

dns.lookupService('127.0.0.1'.80.function(err, hostname, service) {
  if (err) throw err
  console.log('Hostname: %s, service type: %s', hostname, service) // Host name: localhost, service type: HTTP
})
Copy the code

reference

Node. Js Chinese website

IT record

Afterword.

If you like front end like me, also love to do STH, welcome to pay attention to me to play together ~ ❤️

blog

My blog

The public,

Front end moment