From the NodeJS course at Coderwhy.

Express summary: juejin.cn/post/701653…

Koa concludes: juejin.cn/post/701658…

Nodejs website: nodejs.org/dist/latest…

What is Nodejs

Node.js is a JavaScript runtime environment based on the V8 JavaScript engine.

V8 Engine Principle

The Parse module converts JavaScript code into an AST (abstract syntax tree) because the interpreter does not know JavaScript code directly;

  • If the function is not called, it is not converted to an AST;
  • V8. dev/blog/scanne…

Ignition is an interpreter that converts the AST to ByteCode

  • Information is collected for TurboFan optimizations (such as the type of function parameters needed to perform real calculations).
  • If the function is only called once, Ignition will do the interpretation of ByteCode;
  • V8. dev/blog/igniti…

TurboFan is a compiler that compiles bytecode into machine code that the CPU can execute directly.

  • If a function is called multiple times, it is marked as a hot function, which TurboFan converts into optimized machine code to improve code execution.
  • However, the machine code is actually reverted to ByteCode. This is because if the type of the sum function changes during subsequent execution (for example, the sum function used to execute number and then changed to string), the optimized machine code will not handle the operation correctly and will be reversely converted to ByteCode.
  • TurboFan V8 official documentation: V8. Dev /blog/ Turbof…

Here’s how the JavaScript code executes. In fact, V8’s memory reclamation is another reason for its power, but I won’t go into that for now:

  • Orinoco module, responsible for garbage collection, the program will not need memory reclamation;
  • V8. dev/blog/trash-…

Node. Js framework

  • The JavaScript code we write goes through the V8 engine, through node.js Bindings, and puts tasks into the Libuv event loop;
  • Libuv (Unicorn Velociraptor) is a library written in C language;
  • Libuv provides event loops, file system reads and writes, network IO, thread pools, and more;

Nodejs global object

Some useful global objects.

  • __dirname: Gets the absolute path of the current file folder
  • __filenameGet the absolute path to the current file:
  • processObject:
    • CWD (): obtains the absolute path of the current terminal running folder.
    • Argv: Gets the arguments passed in at terminal execution.
    • Env: Gets the environment variable of the current program.

Node. Js modular

CommonJS is supported and implemented in Node, so that we can easily carry out modular development in the process of Node development:

  • Each JS file in Node is a separate module;
  • This module contains the core variables of the CommonJS specification:Exports, module. Exports, require;
  • exportsandmodule.exportsCan be responsible for the content of the module export;
  • requireFunctions can help you import content from other modules (custom modules, system modules, third-party library modules).

Exports, module. Exports, require.

  • Exports is an object to which you can add a number of properties. The added properties are exported;
  • We can also export an object directly through module.exports.
  • We’re throughrequire()The import function imports a file. And the file exports variables.

Exports of module. Exports.

  • There is no module. Exports concept in CommonJS;
  • But to export modules, Node uses Module classes. Each Module is an instance of the Module.
  • Node exports are not exports at all, they are module.exports;
  • Because Module is the real implementer of the export;
  • And inside will beexportsAssigned tomodule.exports.

This method of import and export has one feature.

For details, please visit:Juejin. Cn/post / 701299…

  • The files in Node run in a function. You can printconsole.log(arguments.callee + "")To verify.
  • An import or export is a reference to a value. If the export is a value of a primitive data type, the export file changes the value and the import file does not change the value of the variable.
  • It is imported via the require function, and module dependencies are not known until the JS code is executed.
  • The code is executed synchronously.
  • Modules are introduced multiple times and only loaded once. A loaded module exists inside each module to determine whether it has been loaded
  • When code loops are introduced, depth-first loads modules. Then breadth first.

The path module

This section introduces only some commonly used apis

Because different operating systems may use different path separators, the join method is useful.

  • Resolve: indicates a path to be joined. This will depend on whether there is one before the first path passed in/,.. /,. /To find the local full directory, and then concatenate the other paths passed in. If the first incoming path/The path will be concatenated to the absolute path of the current execution file. If the last incoming path passes/At the beginning, we will simply ignore the path argument passed in earlier.
  • Join: joins paths. This is what’s passed in and what’s spliced in. Foolproof splicing. But also according to.. / to splice the previous level
    const { resolve, join } = require("path")

    const first = '/zhang';
    const second = "./hao" || '.. /hao'
    const third = './llm' || '/llm'

    console.log(resolve( first, second, third)) //C:\zhang\hao\llm || C:\hao\llm || C:\llm
    console.log(join(first, second, third)) // \zhang\hao\llm || \hao\llm || \zhang\hao\llm
Copy the code

  • Dirname: Gets the parent folder of the file;
  • Basename: Obtains the file name.
  • Extname: obtain the file extension.
    const path = require("path")

    const url = "c:/zh/study/nodejs/index.js";

    console.log(path.dirname(url))// c:/zh/study/nodejs 
    console.log(path.basename(url))// index.js
    console.log(path.extname(url))//.js
Copy the code

Fs module

There are three ways to implement most of the FS module apis.

  • Method 1: synchronize operation files: the code will be blocked and will not continue execution;
  • Method 2: asynchronous callback function operation file: the code is not blocked, the callback function needs to be passed, when the result is obtained, the callback function is executed;
  • Method three: asynchronous Promise operation file: code will not block, passfs.promisesCalling a method operation returns a Promise, which can be processed by then and catch;

Method 1: Synchronize files

// 1. Method 1: Read files synchronously
const state = fs.statSync('.. /foo.txt');
console.log(state);

console.log('Subsequent code execution');
Copy the code

Method 2: Asynchronous callback functions operate files

// 2. Mode 2: Read data asynchronously
fs.stat(".. /foo.txt".(err, state) = > {
  if (err) {
    console.log(err);
    return;
  }
  console.log(state);
})
console.log("Subsequent code execution");
Copy the code

Method three: Asynchronous Promise operation file

// 3
fs.promises.stat(".. /foo.txt").then(state= > {
  console.log(state);
}).catch(err= > {
  console.log(err);
})
console.log("Subsequent code execution");
Copy the code

Obtain the file description

    const fs = require("fs");

    fs.stat("./01.hello.txt".(err, info) = > {
      console.log(info)
      console.log(info.isFile())// Check whether it is a file
      console.log(info.isDirectory())// Check whether it is a folder
    })
Copy the code

File descriptor

On POSIX systems, the kernel maintains a table of currently open files and resources for each process.

Each open file is assigned a simple numeric identifier called the file descriptor.

At the system level, all file system operations use these file descriptors to identify and track each particular file.

Windows systems use a different but conceptually similar mechanism to track resources.

To simplify the user’s life, Node.js abstracts out specific differences between operating systems and assigns a numeric file descriptor to all open files

    const fs = require("fs");

    fs.open("./01.hello.txt".(err, fd) = > {
      if (err) {
        console.log(err)
      } else {
        console.log(fd) // fd is a number.
        fs.promise.readFile(fd).then(res= > {
          console.log(res)
        })
      }
    })
Copy the code

File to read and write

Fs. readFile(path[, options], callback) : reads the contents of the file; Fs.writefile (file, data[, options], callback) : Write to a file;

    const fs = require("fs");


    fs.writeFile("./01.hello.txt"."Add file", { encoding: 'utf-8'.flag: 'a+' }, (err, res) = > {
      if (err) {
        console.log(err)
      } else {
        console.log(res)
      }
    })
Copy the code

It is easy to call the read/write API to manipulate files. Let’s illustrate some options.

Encoding: Specifies the encoding format. Note that if the encoding format of the read and write files is different, garbled characters will be generated. Generally, utF-8 encoding is used. If the file read does not specify an encoding format, it returns Buffer data.

Flag: specifies the file writing mode. Flags with + can be read and written. All + flags can be created automatically, except that r+ files do not exist and exceptions are reported when read or written.

Folder operation

  • Create a new folder using fs.mkdir() or fs.mkdirsync ().
    const dirname = './zh';
    if(! fs.existsSync(dirname)) {// Check whether the folder exists
      fs.mkdir(dirname, err= > {
        console.log(err);
      });
    }
Copy the code
  • fs.readdir(), fs.readdirSync()Read all files and folders in a folder
    fs.readdir(dirname, (err, files) = > {
      console.log(files);
    });
Copy the code
  • rename()Rename folders
    fs.rename("./zh"."./llm".err= > {
      console.log(err);
    })
Copy the code

Brothers, master file operation, can do more SAO operation, write a lot of convenient script.

The event module

  • On, listening for events
  • Emit, send events
  • Off: Removes the event. You need to specify the event name and event
  • Once: The command is executed only once
  • RemoveAllListeners delete all events, or pass event names to remove specific events.
  • EventNames () gets all eventNames.
  • ListenerCount (Event name) Gets the number of events currently registered.
  • Gets an array of current events.
    const EventEmitter = require("events");


    const events = new EventEmitter();

    // Listen on events
    events.addListener("zhanghao".(. args) = > {
      console.log("AddListener listening". args) })const listener1 = (. args) = > {
      console.log("On listening". args) } events.addListener("llm", listener1)

    // events.off("llm", listener1)

    // Register events
    events.removeAllListeners("llm")
    events.emit("zhanghao"."I")
    events.emit("llm"."His")

    console.log(events.listenerCount('zhanghao'))
    console.log(events.listeners('llm'))
Copy the code

Buffer

Common ways to create buffers

  • from
    // The encoding and decoding methods are different, decoding will appear gibberish.
    const buf = Buffer.from("Go China!".'utf16le');

    For UTF-8 encoded Chinese characters, a Chinese character is equal to 3 bytes, and for UTF16LE encoded Chinese characters, a Chinese character is equal to 2 bytes
    console.log(buf)

    console.log(buf.toString("utf16le"))// Specify the encoding, otherwise the default is UTF-8 encoding, will be garbled.
Copy the code
  • Alloc (specifies the size of the cache to be created)

    // buf is equivalent to a byte array. When the array is not assigned, it is equivalent to 0000000... placeholder
    const buf = Buffer.alloc(10);

    console.log(buf) //<Buffer 00 00 00 00 00 00 00 00 00 00>


    // Assign to buffer
    buf[0] = 0x90; // For display purposes, the output is hexadecimal to represent binary. Four digits equals a hexadecimal number. So two hexadecimal numbers represent one byte

    console.log(buf)// <Buffer 90 00 00 00 00 00 00 00 00 00>
Copy the code

Read binary files (videos, images, etc.) and do something with them

We can use the Sharp library or jimP library to manipulate images

Github.com/lovell/shar…

www.npmjs.com/package/jim…

    // Make simple changes to the image and output it
    const sharp = require("sharp");
    sharp('./sun.jpg')
      .resize(200.200)
      .toFile("sunCopy.jpg")
Copy the code

The stream flow

What is the flow

Streaming in a program has a similar meaning. We can imagine that when we read data from a file, the binary (byte) of the file is constantly being read into our program. And this string of bytes is the stream in our program. All streams are instances of EventEmitter

Before we learned to read and write files, we can directly read and write files through readFile or writeFile, why still need stream?

  • The direct way of reading and writing files, although simple, but can not control some details of the operation. For example, where to read from, where to read, how many bytes to read at a time;
  • Pause reading at a certain point, resume reading at a certain point, and so on;
  • Or the file is too large, like a video file, to read all at once;

There are four basic flow types in Node.js:

  • Writable: A stream to which data can be written (for example fs.createWritestream ()).
  • Readable: A stream from which data can be read (for example, fs.createreadStream ()).
  • Duplex: streams that are both Readable and Writable (for example, net.socket).
  • Transform: Duplex can modify or Transform streams of data as they are written and read (for example, zlib.createDeflate()).

Let’s look at readable and writable streams:

Readable Readable stream

Previously, fs.readfile () was used to read all the contents of a file into the program (memory) at once. And the read location cannot be specified. So we need to read the file through fs.createreadStream (path, options). After the file is read, the file is automatically closed.

  • start: Position from which to start reading (starting from 0)
  • end: End position
  • highWaterMark: How many bytes a file reads at a time. The default 64 KB
  • encoding: Encoding format
  • flags: Indicates the file id. The default isr
  • .
    const fs = require("fs");

    const read = fs.createReadStream("./zh.txt", {
      // The position starts at 0
      start: 3.end: 8.highWaterMark: 2.// How many bytes a file reads at a time. The default 64 KB
      encoding: 'utf-8'
    })

    // File reading can be paused and resumed using pause(),resume() methods.
    read.on("data".(data) = > {
      console.log(data)
    })
    read.on("open".() = > {
      console.log("File open")
    })
    read.on("close".() = > {
      console.log("File closed")
    })

    read.on("end".() = > {
      console.log("File read complete")})Copy the code

Writable Writable stream

Previously, fs.writefile () was used to write files, and only to overwrite or append the source file. So we need to write the file exactly through the readable stream fs.createWritestream (Path, options).

Options is used to restrict writing to files.

  • start: Position from which to start reading (starting from 0)
  • encoding: Encoding format
  • flags: Indicates the file id. The default isw.
    const fs = require("fs");

    const writeStream = fs.createWriteStream("./zh.txt", {
      flags: 'r+'.// There may be a bug here, so you should specify r+.
      encoding: 'utf-8'.start: 4
    })

    // Write to overwrite the text in the original position.
    writeStream.write("0000".(err) = > {
      console.log(err)
    })
    
    // The end method can write things and also automatically close the file.
    writeStream.end("What is written to the file")

    writeStream.on("open".() = > {
      console.log("File about to be written")})// writeStream.close()

    writeStream.on("close".() = > {
      console.log("File closed")})Copy the code

pipe

Joins writable and readable streams.

Readable streams =====pipe=====> writable streams

    const fs = require('fs');


    const reader = fs.createReadStream("./zh.txt");
    const writer = fs.createWriteStream("./llm.txt");


    // Pipe will automatically close. We don't need to call the close event manually.
    reader.pipe(writer)

    writer.on("close".() = > {
      console.log("File will be closed")})Copy the code

The HTTP module

What is a Web server?

When an application (client) needs a resource, it can request the resource from a server through Http. The server that provides the resources is a Web server;

Creating a Server

    const http = require("http");



    / / way
    const server = new http.Server((req, res) = > {
      res.writeHead(200, {
        'content-type': 'text/html; charset:ASCII'
      })

      res.end("

I am a Chinese character, when the encoding format is ASCII, look at the disorderly code

"
)// it will be garbled. The charset: UTF-8 format is required. }) server.listen(8080.() = > { console.log("Server created successfully")})// Call the Server class. http.createServer((req, res) = > { // Specify the form of the data in the body // req.setEncoding("utf-8") req.setEncoding("binary") req.on("data".(data) = > { console.log("data".typeof data) //string res.end(data) }) // res.end(" return data ") }).listen(3030.() = > { console.log("Server started on port 3030")})Copy the code

The Server uses the Listen method to start the Server and listen for network requests on a host or port:

The listen function takes three arguments:

  • Port: you can use server.address(). Port to get the port number, which will be written into the environment variable in the following project.

  • Host: you can usually pass localhost, IP address 127.0.0.1, or IP address 0.0.0.0. The default is 0.0.0.0.

    • Localhost: is essentially a domain name that is normally resolved to 127.0.0.1;

    • 127.0.0.1: Loop Back Address (127.0.0.1) : Loop Back Address (127.0.0.1) Normal packets pass through application layer-transport layer-network layer-data link layer-physical layer. However, the loopback address is directly obtained at the network layer and is not often at the data link layer and physical layer. For example, if you listen on 127.0.0.1, you cannot access hosts on the same network segment using the host IP address.

    • 0.0.0.0: listen on all IPV4 addresses and find different applications by port; For example, when we listen for 0.0.0.0, hosts in the same network segment can be accessed by IP address. Callback function: the callback function when the server is successfully started;

Parsing query parameters

We can parse the req.url module to retrieve the query. The Query field is then parsed through the QueryString module to generate an object.

const url = require("url")
const queryString = require("querystring")
const {query} = url.parse(req.url);
const queryObj = queryString.parse(query);
Copy the code

Url parsing

    const url = require("url");
    console.log(url.parse("Http://127.0.0.1/user/1? name=zh&age=20#llm"))
Copy the code

Parse the parameters in the request body

Because request is a stream. So we read the incoming data from the POST request, which we need to read by listening for the Data event, and then turn the binary stream into a string. The string is then parsed through json.parse ().

      let dataBody = ""
      // Set the body encoding
      req.setEncoding("utf-8")
      req.on("data".(data) = > {
        dataBody += data; // When the input type cannot be completely obtained, multiple concatenations are needed to obtain the complete data.
      })
      req.on("close".() = > {
        // Parses the parameters before the file is closed
        const requestData = JSON.parse(dataBody)
        console.log(requestData)
      })
Copy the code

Request and corresponding fields

Request header field

Content-type: Specifies the type of the incoming data. Request body type

  • The application/json representation is a JSON type;
  • Text /plain indicates a text type;
  • The application/ XML representation is of XML type;
  • Multipart /form-data indicates that the file is uploaded.

Content-length: indicates the length of data to be transmitted.

Accept-encoing: tells the server the file compression format supported by the client.

Accept: Tells the server that the client accepts the file format type.

In response to the response

The response can only be terminated by the res.end() method. And returns a response.

Write method: This method writes out data directly, but does not close the stream. Setting status code:

  • Res. StatusCode = “”.
  • Res.writehead (” status code “, {response header})

Setting the response header

  • res.setHeader()

Note: Text/HTML means that the response field returns an HTML file, which can be rendered directly on the page, whereas application/ HTML means that the HTML file is downloaded.

The HTTP status code

HTTP Status Code: a 3-digit Code used to indicate the Status of the web server hypertext Transfer protocol (HTTP) response.

The function of HTTP status code is that the server tells the client the status of the current request response. By status code, you can judge and analyze the running status of the server.

The following are some applicable scenarios of status codes:

  • 100: Before sending POST data to the server, the client asks the server whether the server processes the POST data. If the server does not process the POST data, the client does not upload the POST data. If the server processes the POST data, the client uploads the POST data. It is used for POST big data transmission
  • Generally used for breakpoint continuation, or for loading large files such as video files
  • 301: Permanent redirects are cached. The new domain name replaces the old domain name. If the old domain name is no longer in use, users can use 301 to redirect to the new domain name
  • 302: Temporary redirection is not cached and is often used when unlogged users access the user center and redirect to the login page
  • 304: negotiation cache, tell the client there is a cache, directly use the cache data, return page only header information, is no content part
  • 400: The request cannot be identified by the server because the parameter is incorrect
  • 403: This field is returned when the client is told to access the site or resource in decimal format, for example, on the Internet, and then access the site or resource only through an Intranet IP address
  • 404: The server cannot find the resource, or the server rejects the request without explaining why
  • 503: When the server is down for maintenance, use 503 to respond to requests or nginx to set the rate limit. If the rate limit is exceeded, 503 will be returned
  • 504: The gateway times out

classification

The first digit of the status code determines different response states, including the following:

  • 1: message
  • 2 indicates success.
  • 3 indicates redirection
  • 4 indicates that the request is incorrect
  • 5 indicates a server error
1xx

The delegate request has been accepted and needs to continue processing. This type of response is a temporary response, containing only the status line and some optional response header information, and ending with an empty line

Common ones are:

  • 100 (the client continues to send the request, which is a temporary response) : This temporary response is used to inform the client that some of its requests have been received by the server and have not yet been rejected. The client should continue to send the rest of the request, or ignore the response if the request is completed. The server must send a final response to the client after the request completes
  • 101: The server switches protocols based on client requests, mainly used for WebSocket or HTTP2 upgrades
2xx

Indicates that the request was successfully received, understood, and accepted by the server

Common ones are:

  • 200 (success) : The request was successful and the desired response header or data body will be returned with this response
  • 201 (Created) : The request succeeded and the server created a new resource
  • 202 (Created) : The server has received the request but has not yet processed it
  • 203 (Unauthorized information) : The server successfully processed the request, but the information returned may have come from another source
  • 204 (no content) : The server successfully processed the request, but did not return anything
  • 205 (reset content) : The server successfully processed the request, but did not return anything
  • 206 (Partial) : The server successfully processed some requests
3xx

Indicates that further action is required to complete the request. Typically, these status codes are used for redirects

Common ones are:

  • 300 (multiple options) : The server can perform multiple operations on a request. The server can select an operation based on the requester (User Agent) or provide a list of operations for the requester to select
  • 301 (Permanent move) : The requested page has been permanently moved to a new location. When the server returns this response (a response to a GET or HEAD request), it automatically forwards the requester to the new location
  • 302 (Temporary movement) : The server is currently responding to requests from web pages in different locations, but the requester should continue to use the original location for future requests
  • 303 (Look at other locations) : The server returns this code when the requester should use a separate GET request for a different location to retrieve the response
  • 305 (using a proxy) : The requester can only access the requested web page using a proxy. If the server returns this response, it also indicates that the requester should use a proxy
  • 307 (temporary redirection) : The server currently responds to requests from web pages in different locations, but the requester should continue to use the original location for future requests
4xx

Represents that the client appears to have made an error that interferes with the server’s processing

Common ones are:

  • 400 (error request) : The server does not understand the syntax of the request
  • 401 (unauthorized) : Request requires authentication. The server may return this response for a web page that requires login.
  • 403 (Forbidden) : The server rejected the request
  • 404 (not found) : The server could not find the requested page
  • 405 (method disabled) : Disables the method specified in the request
  • 406 (not accepted) : Web page that cannot respond to a request using the requested content features
  • 407 (Proxy authorization required) : This status code is similar to 401 (unauthorized), but specifies that the requester should authorize the use of the proxy
  • 408 (Request timeout) : Timeout occurred while the server was waiting for a request
5xx

Indicates that the server is unable to complete an obviously valid request. This type of status code indicates that an error or exception has occurred while the server is processing the request

Common ones are:

  • 500 (server internal error) : The server encountered an error and could not complete the request
  • 501 (not yet implemented) : The server does not have the capability to complete the request. For example, the server may return this code if it does not recognize the request method
  • 502 (error gateway) : The server acting as a gateway or proxy received an invalid response from the upstream server
  • 503 (Service unavailable) : The server is currently unavailable (due to overloading or downtime for maintenance)
  • 504 (gateway timeout) : The server acts as a gateway or proxy, but does not receive the request from the upstream server in time
  • 505 (HTTP version not supported) : The server does not support the HTTP protocol version used in the request

Event loop

What is an event loop?

I actually think of the event loop as a bridge between the JavaScript we write and the browser or Node.

The browser event loop is a bridge between the JavaScript code we write and the browser API calls (setTimeout/AJAX/ listening for events, etc.) that they communicate with via callback functions.

Node’s event loop is a bridge between the JavaScript code we write and the system calls (File System, network, etc.) they communicate through callbacks.

Event loops in the browser

The main thread

Macro task queue: Ajax, setTimeout, setInterval, DOM listening, UI Rendering, etc

Microtask queues: THEN callbacks for promises, Mutation Observer APIS, queueMicrotask(), and so on

The callback function in the queue is added to the queue only if the condition is met.

When the program in the main thread finishes executing, it looks to see if there are any events in the microtask queue and puts them on the call stack if there are. When the microtask queue completes, it invokes the event in the macro task queue. In the meantime, if the event in the macro task also produces a microtask, it will execute the event in the microtask queue.

Events in the macro task queue will not be executed as long as there are events in the microtask queue. Knows that the event in the microtask queue is finished.

Event loops in Node.js

EventLoop is implemented in browsers according to the specification defined by HTML5. Different browsers may have different implementations, but Node is implemented by Libuv.

Libuv maintains an EventLoop and worker Threads;

  • EventLoop is responsible for invoking other operations of the system: file IO, Network, child-processes, and so on

Libuv is a multi-platform library focused on asynchronous IO. It was originally developed for Node, but is now used in Luvit, Julia, PYUv, and other places;

Blocking AND non-blocking I/OS

The operating system provides blocking and non-blocking calls:

  • Blocking call: The current thread is blocked until the result of the call is returned (blocked CPUS do not allocate time slices), and the calling thread will not continue to execute until it gets the result of the call.
  • Non-blocking calls: After the call is executed, the current thread does not stop executing. It just needs to wait for a while to check if the result is returned.

So many of the time-consuming operations in our development can be called on a non-blocking basis like this:

  • For example, the network request itself uses Socket communication, and Socket itself provides a SELECT model, which can work in a non-blocking manner.
  • For file read/write IO operations, we can use the event-based callback mechanism provided by the operating system.

Problems with non-blocking IO:

However, there are some problems with non-blocking IO: we don’t get the result that we need to read (let’s use read as an example), which means that we frequently need to determine whether the data we read is complete in order to know whether the data we read is complete; This process is called rotation operation;

Libuv provides a Thread Pool. The Thread Pool takes care of all related operations and waits for results through rotation training, etc. When the result is retrieved, the corresponding callback can be placed in an event loop (an event queue); The event loop takes over the subsequent callback and tells the JavaScript application to execute the corresponding callback function.

The event loop phase in Node.js

  • Timers: This stage executes scheduling callbacks that have been set by setTimeout() and setInterval().
  • Pending Callback: Performs a Callback for certain system operations (such as TCP error types), such as ECONNREFUSED when TCP connections are received.
  • Idle, prepare: used only in the system.
  • Poll: Retrieves new I/O events. Perform I/ O-related callbacks;
  • Detection: The setImmediate() callback function executes here.
  • Closed callback functions: Some closed callback functions, such as socket.on(‘close’,…) .

Macro and micro tasks in Node.js

Node’s event loop is more complex in terms of the Tick of an event loop, which is also divided into microtasks and macro tasks:

  • Macrotask: setTimeout, setInterval, IO events, setImmediate, Close events

  • Microtasks: Promise’s then callback, process.nextTick, queueMicrotask;

However, the event loop in Node is not just about microtask queues and macro task queues:

Microtask queue:

  • Next tick queue: process.nextTick;

  • Other queue: Promise’s then callback, queueMicrotask;

Macro task queue:

  • Timer queue: setTimeout, setInterval;

  • Poll Queue: INDICATES I/O events.

  • Check queue: setImmediate;

  • Close queue: Close events;

An interview question

The following code outputs the result

    setTimeout(() = > {
      console.log("setTimeout")},0)

    setImmediate(() = > {
      console.log("setImmediate")})// Who prints the above code first?Both are possible because the Libuv library handles event loops at different times. And it's gonna stay in the IO for a long time, so if I'm doing this,setTimeoutThe function is not added to the Timers queue; setImmediate executes first and vice versasetTimeoutTo perform first.Copy the code