Maison > interface Web > js tutoriel > le corps du texte

Parlons de modularisation et de boucle d'événements dans Nodejs

青灯夜游
Libérer: 2021-07-01 19:08:43
avant
2028 Les gens l'ont consulté

Cet article vous guidera à travers la modularisation et la boucle d'événements dans Nodejs. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer. J'espère qu'il sera utile à tout le monde.

Parlons de modularisation et de boucle d'événements dans Nodejs

5.20 a publié un Ide en ligne qui peut exécuter Node.js sur le navigateur —WebContainers

1 Introduction à Node.js

Qu'est-ce que Node.js exactement ? Quand j'ai commencé à apprendre, je n'avais pas beaucoup de contacts avec certains domaines de connaissances front-end (bien sûr, j'ai toujours la même chose aujourd'hui. Mon impression de Node.js est que sa syntaxe est presque la même que Javascript, et puis je). écrire le back-end. Je me souviens avoir été secrètement heureux à l'époque, apprendre Javascript = tout savoir ! Bon, allons droit au but

[Apprentissage recommandé : "Tutoriel nodejs"]

Dans le passé, Javascript était exécuté sur le navigateur. Javascript est un haut niveau. niveau langage.Ordinateur Il ne peut pas être lu directement.Après tout, il n'y a que 010101 dans le monde informatique binaire. À l'heure actuelle, le moteur JavaScript du navigateur agit comme un traducteur, traduisant étape par étape ce que JavaScript veut faire. . Je n’entrerai pas dans les détails du processus de compilation (je ne peux pas encore l’expliquer).

Node.js est basé sur le moteur V8 du navigateur Chrome et peut compiler efficacement Javascript, on peut donc dire que Node.js est un autre environnement d'exécution Javascript en plus du navigateur.

Je me souviens avoir lancé une simple réponse automatique pour un compte public WeChat sur les fonctions cloud de Tencent Cloud. A cette époque, j'avais une petite expérience avec la modularisation du code front-end, grâce à Node.js !

2 Première expérience

Le fichier server.js est le suivant

// 引入 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端口
Copier après la connexion

Exécutez-le dans le terminal après l'installation de Nodenode server.js Ouvrez le navigateur, dans Entrez http://localhost:3000/ dans la barre d'adresse et vous verrez la page imprimée :

Parlons de modularisation et de boucle dévénements dans Nodejs

À ce stade, nous configurons le serveur le plus simple localement, et le navigateur sert en tant que client pour accéder à la

2.1 Modularisation

Dans le code ci-dessus, nous avons remarqué qu'il y a une instruction comme var http = require("http");, qui est utilisée pour introduire le http module. Dans Node, les modules sont divisés en deux catégories : l'une est le module fourni par Node, appelé module principal ; l'autre est le module écrit par l'utilisateur, appelé module de fichier http est l'un des modules principaux. Par exemple, vous pouvez utiliser le module http pour créer des services, path Le module gère les chemins de fichiers. Le module url est utilisé pour traiter et analyser les URL. Le module fs est utilisé pour lire et écrire les fichiers système. et répertoires.

2.1.1CommonJS

En matière de modularité, il faut mentionner que CommonJS adopte une partie de la syntaxe CommonJS. CommonJS est un standard modulaire au début, afin de résoudre le problème de l'introduction de < via la balise script 🎜>L'ordre des dépendances généré par le code du fichier est sujet aux erreurs et aux problèmes tels que la pollution variable causée par top-. portées de niveaujs

Ici, vous pouvez trier les différences entre l'exportation

et module.exportsexports

test2.js comme suit :

let str = require(&#39;./test1&#39;);
console.log(str)
Copier après la connexion

Lorsque test1.js est comme suit :

let str1 = &#39;小林别闹1&#39;
let str2 = &#39;小林别闹2&#39;

exports.str1 = str1
exports.str2 = str2
console.log(module.exports === exports)
Copier après la connexion

Exécuter dans le terminal

Le résultat est le suivant : node test2.js

/*输出
{ str1: &#39;小林别闹1&#39;, str2: &#39;小林别闹2&#39; }
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: &#39;小林别闹1&#39;, str2: &#39;小林别闹2&#39; }
*/
Copier après la connexion

Vous pouvez faire un résumé :

dans Lorsque Node exécute un fichier, il générera un objet

et un objet exports dans le fichier, et cet objet module a un attribut appelé module, exports est une référence à exports, ils pointent vers la même adresse, mais le final l'exportation est module.exports. Le deuxième test module.exports a changé l'adresse, donc module.exports = str2 n'a pas été exporté str1

Notez également qu'utiliser

pour exporter revient à exporter un objetexports

.

2.1.2 Module Es

Javascript se développe et progresse également constamment Non, la version

a ajouté le Es6moduleEs Module

Export :

.

export const str1 = &#39;小林别闹1&#39;
export const str2 = &#39;小林别闹2&#39;
export default {
    fn() {},
    msg: "小林别闹"
}
Copier après la connexion

Importer :

import { st1,str2,obj } from &#39;./test.js&#39;
Copier après la connexion

Notez

que si vous exécutez le fichier import js directement, une erreur sera signalée. Vous devez le compiler avec babelnode

Si vous le faites. comparez-le, c'est :

CommonJs peut charger dynamiquement des instructions, et le code se produit au moment de l'exécution

Le module Es est statique et ne peut pas charger dynamiquement des instructions. Il ne peut être déclaré qu'en haut. du fichier, et le code apparaît au moment de la compilation.

2.1.3 Modules tiers

En plus d'utiliser ses propres modules de base et modules personnalisés dans Node. , vous pouvez également utiliser des

modules tiers

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

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

2.2 Node 的事件循环

2.2.1 非阻塞I/O

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

console.log(&#39;1&#39;)
setTimeout(() => {
  console.log(&#39;2&#39;)
})
console.log(&#39;3&#39;)//输出132
Copier après la connexion

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

2.2.2事件循环

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

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

console.log(&#39;start&#39;)
setTimeout(() => {//定时器1
  console.log(&#39;timer1&#39;)
  setTimeout(function timeout () {//定时器2
    console.log(&#39;timeout&#39;);
  },0);
  setImmediate(function immediate () {//定时器3
    console.log(&#39;immediate&#39;);
  });
  Promise.resolve().then(function() {
    console.log(&#39;promise1&#39;)
  })
}, 0)
setTimeout(() => {//定时器4
  console.log(&#39;timer2&#39;)
  Promise.resolve().then(function() {
    console.log(&#39;promise2&#39;)
  })
}, 0)
Promise.resolve().then(function() {
  console.log(&#39;promise3&#39;)
})
console.log(&#39;end&#39;)
Copier après la connexion

可以 Node 上边运行一下

Parlons de modularisation et de boucle dévénements dans 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

Parlons de modularisation et de boucle dévénements dans 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
Copier après la connexion

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

Parlons de modularisation et de boucle dévénements dans Nodejs

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

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

Parlons de modularisation et de boucle dévénements dans Nodejs

Parlons de modularisation et de boucle dévénements dans Nodejs

Le code ci-dessus est expliqué comme suit : exécuter sur la première ligne de code, afficher 1, exécuter sur la deuxième ligne de code setTimeout, qui appartient à la macro-tâche 1, se préparer à rejoindre la file d'attente des tâches après 1000 millisecondes, puis exécutez la fonction run, sortie 5, en raison de l'existence de await, nous devons attendre que la fonction fn termine son exécution. Ici, la fonction asynchrone est transformée en fonction synchrone. via le mot-clé await. Lorsque fn est exécuté, 3 est affiché et une autre apparaît setTimeout Tâche macro 2, le temps de préparation est de 20 millisecondes, renvoie l'état de réussite Promise, affiche 6, for La boucle prend 150 ms, c'est la macro tâche 2, la préparation est terminée, entrez dans la file d'attente des tâches, continuez vers le bas, il y a Une setTimeout la macro tâche 3 n'a pas besoin d'être préparée pour rejoindre la file d'attente des tâches. ligne de code et sortie 10. À ce stade, toutes les tâches synchrones ont été exécutées. Vient ensuite la tâche asynchrone est la structure de données de la file d'attente et suit la règle du premier entré, premier sorti. à ce moment, il y a la macro-tâche 2 et la macro-tâche 3 dans la file d'attente des tâches. La macro-tâche 2 est exécutée en premier et 4 est sortie, puis la macro-tâche 3 est exécutée et 7 est sortie elle-même et promise. 8 est sorti. , le code à l'intérieur du rappel then est une microtâche Après l'exécution de la macrotâche 3, on constate qu'il y a une microtâche et une sortie 9 de l'ensemble. processus, la macrotâche 1 rejoint la file d'attente des tâches et sort 2

C'est peut-être plus facile à comprendre si vous lisez directement le blog d'un grand frère ici, je n'arrive pas à l'écrire si bien Désolé, le lien. est ci-dessous.

J'ai honte si je n'écris pas bien, mais je vais étudier dur ! ! !

Pour plus de connaissances sur la programmation, veuillez visiter : Vidéo de programmation ! !

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:juejin.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!