Le module VM est le module principal de NodeJS. Il prend en charge la méthode require et le mécanisme de fonctionnement de NodeJS. Parfois, nous pouvons également utiliser des modèles de VM pour effectuer certaines choses spéciales. Cet article vous donnera une compréhension détaillée du module VM dans Node J'espère qu'il vous sera utile !
Référence machine virtuelle vm | Site officiel de Node
http://nodejs.cn/api/vm.html
Dans l'article précédent, nous avons mentionné un problème.
Comment une chaîne peut-elle être transformée en JS pour exécution ?
Nous avons présenté deux méthodes en détail, à savoir eval function et new Function.
Nous devons souligner à nouveau ici que les fonctions créées par le constructeur Function
ne créent pas de fermetures de l'environnement actuel. Elles sont toujours créées dans l'environnement global, elles ne sont donc accessibles qu'au moment de l'exécution. les variables et leurs propres variables locales ne peuvent pas accéder aux variables dans la portée dans laquelle elles ont été créées par le constructeur Function
. Ceci est cohérent avec l'utilisation du eval
Function
构造器创建的函数不会创建当前环境的闭包,它们总是被创建于全局环境,因此在运行时它们只能访问全局变量和自己的局部变量,不能访问它们被 Function
构造器创建时所在的作用域的变量。这一点与使用 eval
执行创建函数的代码不同。
global.a = 100; // 挂在到全局对象global上 var b = 200; // this !== global new Function("console.log(a)")() // 100 new Function("console.log(b)")() // b is not defined
Function
可以获取全局变量,所以他还是可能会有变量污染的情况出现。Function
是 模块引擎的实现原理 ,后续我会出一篇文章进行单独讲解。
还有一种解决方案,我们在上一次文章中没有进行详细的展开,那就是 vm
模块 。
在上述文字中,我一直在强调一个概念,那就是 变量的污染。
VM的特点就是不受环境的影响,也可以说他就是一个 沙箱环境 (沙箱模式给模块提供一个环境运行而不影响其它模块和它们私有的沙箱)。
const vm = require('vm') global.a = 100; // 运行在当前环境中[当前作用域] vm.runInThisContext('console.log(a)'); // 100 // 运行在新的环境中[其他作用域] vm.runInNewContext('console.log(a)'); // a is not defined
在这里我们要强调一下,因为 在Node.js中全局变量是在多个模块下共享的,所以尽量不要在global中定义属性。 Demo中的定义是为了方便理解。
假设我们在同级目录下有一个文件 1.js ,里面定义了 global.a = 100;
。 现在我们引入这个文件
requrie(./1); console.log(a); // 100
我们可以发现,在当前文件中我们并没有定义变量a,仅仅只是把两个模块文件关联在了一起。这就是我上面提到的,Node中全局变量是在多个模块下共享的。
他的原理是因为在 Node 的环境中,全局中有一个执行上下文。
// 模拟一下Node的全局环境 // vm.runInThisContext在当前全局环境执行,但不会产生新函数 - function(exports, module, require, __dirname, __filename){ // ... } - vm.runInThisContext ... // vm.runInNewContext在全局环境之外执行 vm.runInNewContext ...
所以,vm.runInThisContext
可以访问到 global
上的全局变量,但是访问不到自定义的变量。而 vm.runInNewContext
访问不到 global
,也访问不到自定义变量,他存在于一个全新的执行上下文。
而我们require
就是通过 vm.runInThisContext
实现的。
实现require
主要可以分为以下四步。
读取需要引入的文件。
读取到文件后,将代码封装成一个函数。
通过 vm.runInThisContext
Le code qui exécute la fonction de création est différent.
// 文件a通过module.exports导出一个变量,在文件b中使用require进行接收。 // a.js module.exports = "a" // b.js let a = require('./a'); console.log(a); // a
Fonction
peut obtenir des variables globales, elle peut donc toujours avoir une pollution variable. Fonction
est le principe d'implémentation du . Je publierai un article pour l'expliquer séparément à l'avenir.
vm
. Dans le texte ci-dessus, j'ai mis l'accent sur un concept qui est la Pollution des variables. La caractéristique de la VM est qu'elle n'est pas affectée par l'environnement. On peut également dire qu'il s'agit d'un environnement sandbox (le mode Sandbox fournit un environnement permettant aux modules de s'exécuter sans affecter les autres modules et leurs bacs à sable privés. ).
let a = module.exports = "a";
Nous voulons souligner ici que parce que les variables globales dans
Node.jsSupposons que nous ayons un fichier 1.js dans le même répertoire, qui définit global.a = 100;
. Maintenant que nous introduisons ce fichier
let a = (function(exports, module, require, __dirname, __filename){ module.exports = "a"; return module.exports })(...args) // exports, module, require, __dirname, __filename 将五个参数传入
nous pouvons constater que nous ne définissons pas la variable a dans le fichier actuel, nous associons simplement les deux fichiers de module ensemble. C'est ce que j'ai mentionné ci-dessus, les variables globales dans Node sont partagées entre plusieurs modules.
La raison est que dans l'environnement de
Node// a.js var a = 100; module.exports = function(){}
Ainsi, vm.runInThisContext
peut accéder aux variables globales sur global
, mais ne peut pas accéder aux variables personnalisées. Cependant, vm.runInNewContext
ne peut pas accéder à global
, ni aux variables personnalisées. Il existe dans un tout nouveau contexte d'exécution. Et notre require
est implémenté via vm.runInThisContext
.
require
peut être divisée en quatre étapes suivantes. 🎜🎜🎜🎜Lisez les fichiers qui doivent être importés. 🎜🎜🎜🎜Après avoir lu le fichier, encapsulez le code dans une fonction. 🎜🎜🎜🎜Convertissez-le en syntaxe JS via vm.runInThisContext
. 🎜🎜🎜🎜Appel à code. 🎜🎜🎜🎜Supposons que nous ayons maintenant les deux fichiers suivants. Ce sont 🎜a.js🎜 et 🎜b.js🎜🎜let a = (function(exports, module, require, __dirname, __filename){ var a = 100; module.exports = function(){}; return module.exports })(...args) // exports, module, require, __dirname, __filename 将五个参数传入
let a = (function(exports, module, require, __dirname, __filename){ module.exports = "a"; return module.exports })(...args) // exports, module, require, __dirname, __filename 将五个参数传入
封装成函数的原因,我们可以参考下面这个例子。
假设我们现在传入的不是字符串,而是一个函数。
// a.js var a = 100; module.exports = function(){}
这样我们在解析的时候,就会被解析成下面这种格式
let a = (function(exports, module, require, __dirname, __filename){ var a = 100; module.exports = function(){}; return module.exports })(...args) // exports, module, require, __dirname, __filename 将五个参数传入
我们导出的是 module.exports
,所以在模块文件中定义的变量a,也只属于当前这个执行上下文。
在解析的时候,变量a 会被放到函数中。真正的实现了 作用域分离。
vm.runInThisContext
解析成可执行的Js代码
我们处理过的代码会以字符串的形式存在,所以我们需要通过vm.runInThisContext
将字符串进行解析。
进行代码调用
在此之前,我们其实还需要对代码进行调试。
更多node相关知识,请访问:nodejs 教程!!
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!