Home >Web Front-end >JS Tutorial >Let's talk about modularity and event loop in Nodejs

Let's talk about modularity and event loop in Nodejs

青灯夜游
青灯夜游forward
2021-06-01 11:06:182106browse

This article will take you to understand the modularization and event loop in Nodejs. It has certain reference value. Friends in need can refer to it. I hope it will be helpful to everyone.

Let's talk about modularity and event loop in Nodejs

5.20 released an online Ide that can run Node.js on the browser —WebContainers

1 Introduction to Node.js

What exactly is Node.js? When I started learning, I didn’t have much contact with some front-end knowledge areas (of course I still have the same today). My impression of Node.js is that its syntax is almost the same as Javascript, and then I write the back-end. I remember being secretly happy at the time, learning Javascript = knowing everything! Okay, let’s get to the point

[Recommended learning: "nodejs Tutorial"]

In the past, Javascript was run on the browser. Javascript is a high-level language. Computer It cannot be read directly. After all, there are only 010101 in the binary computer world. At this time, the JavaScript engine in the browser acts as a translator, translating to the computer step by step what JavaScript wants to do. I won’t go into details about the compilation process (I can’t explain it yet).

Node.js is based on the V8 engine of the Chrome browser and can efficiently compile Javascript, so it can be said that Node.js is another Javascript running environment besides the browser.

I remember tossing around with a simple automatic reply for the WeChat public account on Tencent Cloud’s cloud functions. At that time, I had a little experience with the modularization of the front-end code, thanks to Node.js!

2 First experience

The server.js file is as follows

// 引入 http 模块
var http = require("http");

//  用 http 模块创建服务
 //req 获取 url 信息 (request)
 //res 浏览器返回响应信息 (response)
http.createServer(function (req, res) {
  // 设置 HTTP 头部,状态码是 200,文件类型是 html,字符集是 utf8
  //Content-Type字段用于定义网络文件的类型和网页的编码,决定浏览器将以什么形式、什么编码读取这个文件,不写就可能会出现乱码哦
  res.writeHead(200, {
    "Content-Type": "text/html;charset=UTF-8"
  });

  // 往页面打印值
  res.write('小林别闹');

  // 结束响应
  res.end();

}).listen(3000); // 监听3000端口

Run it in the terminal after Node is installednode server.js Open the browser and enter http://localhost:3000/ in the address bar and you will see the page printed:

Lets talk about modularity and event loop in Nodejs

At this time we Build the simplest server locally, and use the browser as a client to access it

2.1 Modularity

In the above code, we noticed that there arevar http = require("http"); Such a statement is used to introduce the http module. In Node, modules are divided into two categories: one is the module provided by Node, called the core module; the second is a module written by the user, called a file module. http is one of the core modules. For example, use the http module to create services, and path module processing File path, url module is used to process and parse URLs. fs module is used to read and write system files and directories, etc.

2.1. 1CommonJS

When it comes to modularization, we must mention CommonJS. Node.js adopts part of the CommonJS syntax. It can be understood that CommonJS is a modular standard. In the early days, in order to solve the problem, it passedscript Tag introductionjsThe dependency sequence generated by the file code is prone to errors, and problems such as variable pollution caused by the top-level scope

Here you can sort out the exportmodule. The difference between exports and exports

test2.js is as follows:

let str = require('./test1');
console.log(str)

When test1.js is as follows:

let str1 = '小林别闹1'
let str2 = '小林别闹2'

exports.str1 = str1
exports.str2 = str2
console.log(module.exports === exports)

Execute in the terminalnode test2.js The results are as follows:

/*输出
{ str1: '小林别闹1', str2: '小林别闹2' }
true
*/

//改变test1.js文件变量暴露的方式
/*
exports.str1 = str1
module.exports = str2
console.log(module.exports === exports)
输出:
false
小林别闹2
*/

/*
exports.str1 = str1
module.exports.str2 = str2
console.log(module.exports === exports)
控制台输出:
true
{ str1: '小林别闹1', str2: '小林别闹2' }
*/

can be summarized:

When Node executes a file, an exports will be generated in the file. object and a module object, and this module object has another attribute called exports, exports is a pair of module.exports references, they point to the same address, but the final export is module.exports, the second test module.exports = str2 changed the address, so str1 is not exported.

Also note that using exports to export is to export an object

2.1.2 Es Module

Javascript is also constantly developing and progressing. No, the Es6 version has added the Es Module module

Export:

export const str1 = '小林别闹1'
export const str2 = '小林别闹2'
export default {
    fn() {},
    msg: "小林别闹"
}

Import:

import { st1,str2,obj } from './test.js'

Noteimport If you execute the node js file directly, an error will be reported. You need to compile it with babel.

If you compare it, it will be:

CommonJs can dynamically load statements, and the code occurs at runtime

Es Module is static, and cannot dynamically load statements. It can only be declared at the top of the file, and the code occurs at compile time

2.1.3 Third-party modules

In addition to using the core modules and custom modules provided by yourself in Node, you can also use third-party modules

这就需要提到 npm ,npm 是 Node 的包管理工具,已经成为了世界上最大的开放源代码的生态系统,我们可以下载各种包.

当然包管理工具还有yarn,但是我暂时只用过 npm,因为它随 node 一起按照提供.

2.2  Node 的事件循环

2.2.1 非阻塞I/O

Java、PHP 或者 .NET 等服务端语言,会为每一个客户端的连接创建一个新的线程。Node 不会为每一个客户连接创建一个新的线程,而仅仅使用一个线程。

console.log('1')
setTimeout(() => {
  console.log('2')
})
console.log('3')//输出132

Javascript 的代码是从上到下一行行执行的,但是这里就不会阻塞,输出3,再输出2

2.2.2事件循环

Node 的事件循环真的好久才弄懂一丢丢,看过很多博客,觉得理解 Node 的事件循环机制,结合代码及其运行结果来分析是最容易理解的。

libuv 库负责 Node API 的执行。它将不同的任务分配给不同的线程,形成一个 Event Loop(事件循环),以异步的方式将任务的执行结果返回给 V8 引擎。其中 libuv 引擎中的事件循环分为 6 个阶段,它们会按照顺序反复运行。每当进入某一个阶段的时候,都会从对应的回调队列中取出函数去执行。当队列为空或者执行的回调函数数量到达系统设定的阈值,就会进入下一阶段。

console.log('start')
setTimeout(() => {//定时器1
  console.log('timer1')
  setTimeout(function timeout () {//定时器2
    console.log('timeout');
  },0);
  setImmediate(function immediate () {//定时器3
    console.log('immediate');
  });
  Promise.resolve().then(function() {
    console.log('promise1')
  })
}, 0)
setTimeout(() => {//定时器4
  console.log('timer2')
  Promise.resolve().then(function() {
    console.log('promise2')
  })
}, 0)
Promise.resolve().then(function() {
  console.log('promise3')
})
console.log('end')

可以 Node 上边运行一下

Lets talk about modularity and event loop in Nodejs

timers 阶段:这个阶段执行timer(setTimeout、setInterval)的回调

I/O callbacks 阶段:处理一些上一轮循环中的少数未执行的 I/O 回调

idle, prepare 阶段:仅node内部使用

poll 阶段:获取新的I/O事件, 适当的条件下node将阻塞在这里

check 阶段:执行 setImmediate() 的回调

close callbacks 阶段:执行 socket 的 close 事件回调

理解:首先执行同步任务,所以会输出start end,poll阶段是事件循环的入口,有异步事件就是从这里进入的,同步任务执行完执行先微任务,输出 promise3,接下来就是 setTimeout了,由 poll阶段一步步到 timers 阶段,执行定时器1,输出 timer1,将定时器2和定时器3加入到队列里边,一旦执行一个阶段里的一个任务就立刻执行微任务队列,所以再输出 promise1,然后执行定时器4,如上输出timer2,promise2,结合事件再循环,到了 check 阶段,执行 setImmediate() 的回调,输出 immediate,再循环进行,到达 timer 阶段,输出 timeout

Lets talk about modularity and event loop in Nodejs

2.2.3浏览器的事件循环

浏览器和 Node 的事件循环是不一样的

打算用两张图和一段代码来解释浏览器的事件循环机制,

console.log(1)
setTimeout(()=>{console.log(2)},1000)//宏任务1
async function fn(){
    console.log(3)
    setTimeout(()=>{console.log(4)},20)//宏任务2
    //return Promise.reject()返回失败状态的,不会输出6,弄不清楚为啥
    return Promise.resolve()
}
async function run(){
    console.log(5)
    await fn()
    //console.log(6),
}
run()
//需要执行150ms左右
for(let i=0;i<90000000;i++){}
setTimeout(()=>{//宏任务3
    console.log(7)
    new Promise(resolve=>{
        console.log(8)
        resolve()
    }).then(()=>{console.log(9)})
},0)
console.log(10)
// 1 5 3 10 4 7 8 9 2

执行结果如(请忽略我的工具提示):

Lets talk about modularity and event loop in Nodejs

我们可以储备一些前置知识:JavaScript 是单线程的,任务可以分为同步任务和异步任务,像 console.log('1') 就是同步的,定时器 setTimeout,promise 的回调等就是异步的。同步的很好理解,就从上到下一行一行的执行下来,异步的就有点小复杂了,还会分为宏任务和微任务。

浏览器的事件循环机制就是:先执行同步任务,同步任务执行完成,就执行任务队列里面的任务,那任务队列里面的任务是哪来的呢?异步任务准备好了就会放进任务队列,你可以理解为,在任务队列里边宏任务和微任务都存在这一个队列结构管着它们。先后的话,同步任务执行完成后,任务队列里有微任务,则将微任务执行完,再执行一个宏任务,执行了宏任务可能又产生了微任务,这是就需要再执行完微任务任务。你可以将同步任务看成宏任务,这样就可以理解为,每执行完一个宏任务都要清理一遍微任务。

Lets talk about modularity and event loop in Nodejs

Lets talk about modularity and event loop in Nodejs

The above code is explained as follows: when the first line of code is executed, 1 is output, and when the second line of code is executed, setTimeout belongs to macro task 1 and is ready to be added to the task queue after 1000 milliseconds. Then execute the function run and output 5. Because of the existence of await, we need to wait for the fn function to be executed. Here, we pass ## The #await keyword turns an asynchronous function into a synchronous one. When fn is executed, 3 is output, and another setTimeout macro task 2 appears, with a preparation time of 20 Milliseconds, return the success status Promise, output 6,for The loop takes 150ms, this is macro task 2, when the preparation is completed, enter the task queue and continue down. , there is a setTimeout macro task 3. There is no need to prepare to join the task queue. Execute the last line of code and output 10. At this point, all synchronous tasks have been executed. Next is the asynchronous task, task queue. It is the data structure of the queue, following the first-in, first-out principle. At this time, there are macrotask 2 and macrotask 3 in the task queue. Macrotask 2 is executed first and 4 is output, and then macrotask 3 is executed and ## is output. #7, promise itself is synchronous, outputs 8, callback then. The code inside is a microtask. After macrotask 3 is executed, it is found that there is The microtask exists. Clean one side of the microtask and output 9. After 1000 milliseconds of the entire process, macrotask 1 joins the task queue and outputs 2. Take a look here. The blog of the older brother may be easier to understand, but the writing is not that good. Sorry, the link is below.

I feel very ashamed if I don’t write well, but I will study hard! ! !

For more programming related knowledge, please visit:

Programming Video

! !

The above is the detailed content of Let's talk about modularity and event loop in Nodejs. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:juejin.cn. If there is any infringement, please contact admin@php.cn delete