Heim  >  Artikel  >  Web-Frontend  >  Ein tiefer Einblick in das VM-Modul in Node.js

Ein tiefer Einblick in das VM-Modul in Node.js

青灯夜游
青灯夜游nach vorne
2021-11-22 19:36:183391Durchsuche

Das VM-Modul ist das Kernmodul in NodeJS. Es unterstützt die Require-Methode und den Betriebsmechanismus von NodeJS. Manchmal verwenden wir auch VM-Vorlagen, um einige spezielle Dinge zu tun. Dieser Artikel vermittelt Ihnen ein detailliertes Verständnis des VM-Moduls in Node. Ich hoffe, er wird Ihnen hilfreich sein!

Ein tiefer Einblick in das VM-Modul in Node.js

Referenz VM virtuelle Maschine |. Offizielle Node-Website

http://nodejs.cn/api/vm.html

Im vorherigen Artikel haben wir ein Problem erwähnt.

Wie kann ein String zur Ausführung in JS umgewandelt werden?

Wir haben zwei Methoden im Detail vorgestellt, nämlich Bewertungsfunktion und Neue Funktion.

Wir müssen hier noch einmal betonen, dass vom Function-Konstruktor erstellte Funktionen keine Abschlüsse der aktuellen Umgebung erzeugen. Sie werden immer in der globalen Umgebung erstellt, sodass auf sie nur zur Laufzeit zugegriffen werden kann Variablen und ihre eigenen lokalen Variablen können nicht auf Variablen in dem Bereich zugreifen, in dem sie vom Function-Konstruktor erstellt wurden. Dies steht im Einklang mit der Verwendung von evalFunction 构造器创建的函数不会创建当前环境的闭包,它们总是被创建于全局环境,因此在运行时它们只能访问全局变量和自己的局部变量,不能访问它们被 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模块

在上述文字中,我一直在强调一个概念,那就是 变量的污染

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 Der Code, der die Erstellungsfunktion ausführt, ist unterschiedlich.

    // 文件a通过module.exports导出一个变量,在文件b中使用require进行接收。
    // a.js
    module.exports = "a"
    // b.js
    let a = require('./a');
    console.log(a); // a
  • Funktion kann globale Variablen abrufen, daher kann es immer noch zu einer Variablenverschmutzung kommen. Funktion ist das Implementierungsprinzip der
  • Modul-Engine

    . Ich werde in Zukunft einen Artikel veröffentlichen, um es separat zu erklären.

  • Es gibt auch eine Lösung, auf die wir im letzten Artikel nicht näher eingegangen sind, und zwar das Modul vm.

vm module

Im obigen Text habe ich ein Konzept hervorgehoben, nämlich Verschmutzung von Variablen. Das Merkmal von VM ist, dass es nicht von der Umgebung beeinflusst wird. Man kann auch sagen, dass es sich um eine Sandbox-Umgebung handelt (Der Sandbox-Modus bietet eine Umgebung, in der Module ausgeführt werden können, ohne andere Module zu beeinträchtigen ihre privaten Sandkästen).

let a = module.exports = "a";

Wir möchten hier betonen, dass globale Variablen in

Node.js
    von mehreren Modulen gemeinsam genutzt werden. Versuchen Sie daher, keine Eigenschaften in global zu definieren. Die Definitionen in der Demo dienen dem besseren Verständnis.
  • Angenommen, wir haben eine Datei 1.js im selben Verzeichnis, die global.a = 100; definiert. Nachdem wir nun diese Datei eingeführt haben

    let a = (function(exports, module, require, __dirname, __filename){
      module.exports = "a";
      return module.exports
    })(...args) // exports, module, require, __dirname, __filename 将五个参数传入

    , können wir feststellen, dass wir die Variable a nicht in der aktuellen Datei definieren, sondern nur die beiden Moduldateien miteinander verknüpfen. Das habe ich oben erwähnt: Globale Variablen in Node werden von mehreren Modulen gemeinsam genutzt.

    Der Grund dafür ist, dass es in der Umgebung von

    Node
  • global einen Ausführungskontext gibt.
  • // a.js
    var a = 100;
    module.exports = function(){}

    vm.runInThisContext kann also auf globale Variablen auf global zugreifen, aber nicht auf benutzerdefinierte Variablen. Allerdings kann vm.runInNewContext nicht auf global zugreifen, noch kann es auf benutzerdefinierte Variablen zugreifen. Es existiert in einem völlig neuen Ausführungskontext. Und unser require wird durch vm.runInThisContext implementiert.

    🎜Die Implementierung von require kann in die folgenden vier Schritte unterteilt werden. 🎜🎜🎜🎜Lesen Sie die Dateien, die importiert werden müssen. 🎜🎜🎜🎜Nachdem Sie die Datei gelesen haben, kapseln Sie den Code in eine Funktion. 🎜🎜🎜🎜Konvertieren Sie es über vm.runInThisContext in JS-Syntax. 🎜🎜🎜🎜Codeanruf. 🎜🎜🎜🎜Angenommen, wir haben jetzt die folgenden zwei Dateien. Sie sind 🎜a.js🎜 und 🎜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 将五个参数传入
    🎜 Wir können die Implementierungslogik von Import und Export anhand der oben genannten vier Schritte analysieren. 🎜🎜🎜🎜🎜Dateien lesen. 🎜🎜🎜Fügen Sie den Inhalt der Datei, die importiert werden muss, in die Datei ein, die empfangen werden muss, und es wird so aussehen🎜rrreee🎜Aber in dieser Form kann Node es überhaupt nicht analysieren, also müssen wir fortfahren der zweite Schritt. 🎜🎜🎜🎜🎜Kapseln Sie die gelesene Datei in eine Funktion. 🎜🎜
    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 教程!!

Das obige ist der detaillierte Inhalt vonEin tiefer Einblick in das VM-Modul in Node.js. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:juejin.cn. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen