Maison  >  Article  >  interface Web  >  Comprendre le système de modules dans Node.js

Comprendre le système de modules dans Node.js

青灯夜游
青灯夜游avant
2020-11-24 17:58:153189parcourir

Comprendre le système de modules dans Node.js

Recommandations associées : "Tutoriel node js"

Module Node.js

JavaScript en A simple Un langage de script permettant d'ajouter des fonctions interactives aux pages Web est sorti. Au début, il n'incluait pas de système de modules. Alors que JavaScript résolvait des problèmes de plus en plus complexes, l'écriture de tous les codes dans un seul fichier et l'utilisation de fonctions pour distinguer les unités fonctionnelles ne pouvaient plus être prises en charge. le développement d'applications complexes. Oui, ES6 apporte des classes et des modules communs à la plupart des langages de haut niveau, permettant aux développeurs d'organiser plus facilement le code

import _ from 'lodash';

class Fun {}

export default Fun;

Les trois lignes de code ci-dessus montrent les deux éléments les plus importants d'un système de module, importation et exportation

  • exportUtilisé pour spécifier l'interface externe du module

  • importUtilisé pour saisir les fonctions fournis par d'autres modules

Avant ES6, de nombreuses solutions de chargement de modules sont apparues dans la communauté, les plus importantes étant CommonJS et AMD. Node.js est né avant ES6, et le système de modules. utilisé une implémentation similaire à CommonJS, suivant plusieurs principes

  • Un fichier est un module, et la portée de la variable dans le fichier est dans le module

  • Utilisez l'objet module.exports pour exporter l'interface externe du module

  • Utilisez require pour introduire d'autres modules

circle.js

const { PI } = Math;

module.exports = function area(r) {
  PI * r ** 2;
};

Le code ci-dessus implémente un module de Node.js , le module ne dépend pas des autres modules et exporte la méthode area pour calculer l'aire d'un cercle

test.js

const area = require('./circle.js');
console.log(`半径为 4 的圆的面积是 ${area(4)}`);

Le module s'appuie sur circle.js et utilise sa méthode de zone exposée pour calculer le cercle L'aire de

module.exports

L'interface externe exposée du module utilise module.exports. Il existe deux usages courants : y ajouter des attributs ou attribuer des valeurs à de nouveaux objets
test.js

// 添加属性
module.exports.prop1 = xxx;
module.exports.funA = xxx;
module.exports.funB = xxx;

// 赋值到全新对象
module.exports = {
  prop1,
	funA,
  funB,
};

Les deux manières d'écrire sont équivalentes, et il n'y a pas de différence quand en les utilisant

const mod = require('./test.js');

console.log(mod.prop1);
console.log(mod.funA());

Il existe une autre façon d'utiliser directement l'objet exports, mais vous ne pouvez lui ajouter que des attributs et ne pouvez pas l'attribuer à un nouvel objet, la raison sera introduite plus tard

.
// 正确的写法:添加属性
exports.prop1 = xxx;
exports.funA = xxx;
exports.funB = xxx;

// 赋值到全新对象
module.exports = {
  prop1,
	funA,
  funB,
};

require('id')

Type de module

l'utilisation de require est relativement simple, id prend en charge deux types : nom du module et chemin du fichier

Nom du module

const fs = require('fs');
const _ = require('lodash');

Le fs et lodash dans l'exemple sont tous deux des noms de module. fs est le module principal intégré de Node.js, et lodash est un module tiers installé sous node_modules via npm s'il apparaît. le nom est le même, privilégiez l'utilisation des modules intégrés au système

Parce qu'un projet peut contenir plusieurs dossiers node_modules (conception relativement ratée de Node.js), le processus de recherche de modules tiers suivra le principe de proximité et remontez couche par couche (vous pouvez imprimer module.paths dans le programme pour afficher le chemin de recherche spécifique) jusqu'à ce que le répertoire racine du système de fichiers soit trouvé selon la variable d'environnement NODE_PATH Pour le processus spécifique, veuillez vous référer. vers la documentation officielle

De plus, Node.js recherchera également la liste du répertoire global suivante :

  • $HOME/.node_modules
  • $HOME/.node_libraries
  • $PREFIX/lib/node

$HOME est le répertoire personnel de l'utilisateur et $PREFIX est le node_prefix configuré dans Node.js. Il est fortement recommandé de placer toutes les dépendances dans le répertoire node_modules local, qui se chargera plus rapidement et sera plus fiable

Chemin du fichier

Les modules peuvent également être chargés en utilisant les chemins de fichiers. C'est le projet. méthode générale de chargement des modules personnalisés dans le module, l'extension du chemin peut être omise et le chemin sera essayé dans l'ordre de .js, .json et .node

  • Modules préfixés par '/' sont les chemins absolus des fichiers. Rechercher les modules en fonction du chemin système
  • Les modules préfixés par './' sont relatifs au fichier appelant actuellement la méthode require et ne sont pas affectés par l'endroit où les modules suivants sont utilisés
  • . 🎜>

Chargement unique et dépendances circulaires Les modules

seront mis en cache dans Module._cache après le premier chargement. Si chaque appel à require('foo') aboutit au même fichier, le même objet sera mis en cache. sera renvoyé et Ne provoquera pas l'exécution multiple du code du module. Node.js met en cache les modules en fonction de leurs noms de fichiers réels, de sorte que le même module n'est pas chargé deux fois lorsqu'il est référencé à partir de répertoires différents. require(foo)

Le mécanisme de chargement unique des modules bien compris facilite notre compréhension du phénomène des dépendances circulaires des modules


a.js

console.log('a 开始');
exports.done = false;
const b = require('./b.js');
console.log('在 a 中,b.done = %j', b.done);
exports.done = true;
console.log('a 结束');

b.js

console.log('b 开始');
exports.done = false;
const a = require('./a.js');
console.log('在 b 中,a.done = %j', a.done);
exports.done = true;
console.log('b 结束');

:main.js

console.log('main 开始');
const a = require('./a.js');
const b = require('./b.js');
console.log('在 main 中,a.done=%j,b.done=%j', a.done, b.done);
Lorsque main.js charge a.js, a.js charge b.js À ce moment, b.js essaiera de charger a.js

Afin d'éviter. boucles infinies Renvoie une

copie inachevée de l'objet d'exportation de a.js au module b.js, puis b.js termine le chargement et fournit l'objet d'exportation au module a.js

Ainsi, le exemple La sortie de est

main 开始
a 开始
b 开始
在 b 中,a.done = false
b 结束
在 a 中,b.done = true
a 结束
在 main 中,a.done=true,b.done=true

看不懂上面的过程也没关系,日常工作根本用不到,即使看懂了也不要在项目中使用循环依赖!

工作原理

Node.js 每个文件都是一个模块,模块内的变量都是局部变量,不会污染全局变量,在执行模块代码之前,Node.js 会使用一个如下的函数封装器将模块封装

(function(exports, require, module, __filename, __dirname) {
	// 模块的代码实际上在这里
});
  • __filename:当前模块文件的绝对路径
  • __dirname:当前模块文件据所在目录的绝对路径
  • module:当前的模块实例
  • require:加载其它模块的方法,module.require 的快捷方式
  • exports:导出模块接口的对象,module.exports 的快捷方式

回头看看最开始的问题,为什么 exports 对象不支持赋值为其它对象?把上面函数添加一句 exports 对象来源就很简单了

const exports = module.exports;
(function(exports, require, module, __filename, __dirname) {
	// 模块的代码实际上在这里
});

其它模块 require 到的肯定是模块的 module.exports 对象,如果吧 exports 对象赋值给其它对象,就和 module.exports 对象断开了连接,自然就没用了

在 Node.js 中使用 ES Module

随着 ES6 使用越来越广泛,Node.js 也支持了 ES6 Module,有几种方法

babel 构建

使用 babel 构建是在 v12 之前版本最简单、通用的方式,具体配置参考 @babel/preset-env(https://babeljs.io/docs/en/babel-preset-env)

.babelrc

{
  "presets": [
    ["@babel/preset-env", {
      "targets": {
        "node": "8.9.0",
        "esmodules": true
      }      
    }]
  ]
}

原生支持

在 v12 后可以使用原生方式支持 ES Module

  • 开启 --experimental-modules

  • 模块名修改为 .mjs (强烈不推荐使用)或者 package.json 中设置 "type": module

这样 Node.js 会把 js 文件都当做 ES Module 来处理,更多详情参考官方文档(https://nodejs.org/dist/latest-v13.x/docs/api/esm.html)

更多编程相关知识,请访问:编程视频!!

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!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer