> 웹 프론트엔드 > JS 튜토리얼 > Node.js의 VM 모듈에 대한 심층 분석

Node.js의 VM 모듈에 대한 심층 분석

青灯夜游
풀어 주다: 2021-11-22 19:36:18
앞으로
3472명이 탐색했습니다.

VM 모듈은 NodeJS의 핵심 모듈이며 NodeJS의 작동 메커니즘을 지원합니다. 때로는 VM 템플릿을 사용하여 몇 가지 특별한 작업을 수행할 수도 있습니다. 이 글이 Node의 VM 모듈에 대해 자세히 이해하는 데 도움이 되기를 바랍니다.

Node.js의 VM 모듈에 대한 심층 분석

참조 vm 가상 머신 | Node 공식 홈페이지

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

이전 기사에서 문제를 언급했습니다.

문자열을 JS로 변환하여 실행하려면 어떻게 해야 하나요?

2가지 방법, 즉 eval functionnew Function을 자세히 소개했습니다.

여기서 Function 생성자로 생성된 함수는 현재 환경의 클로저를 생성하지 않는다는 점을 다시 강조해야 합니다. 이 함수는 항상 전역 환경에서 생성되므로 런타임 전역에서만 액세스할 수 있습니다. 변수 및 자체 지역 변수는 함수 생성자에 의해 생성된 범위의 변수에 액세스할 수 없습니다. 이는 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 생성 기능을 실행하는 코드가 다릅니다.

    // 文件a通过module.exports导出一个变量,在文件b中使用require进行接收。
    // a.js
    module.exports = "a"
    // b.js
    let a = require('./a');
    console.log(a); // a
    로그인 후 복사
  • 함수는 전역 변수를 얻을 수 있으므로 여전히 변수 오염이 있을 수 있습니다. 함수
  • 모듈 엔진

    의 구현 원리입니다. 추후 별도로 설명하는 글을 게시하겠습니다.

  • 지난 기사에서 자세히 설명하지 않은 또 다른 솔루션이 있는데, 바로 vm 모듈입니다.

vm 모듈

위 텍스트에서 저는 변수의 오염. VM의 특징은 환경에 영향을 받지 않는다는 점입니다. 샌드박스 환경이라고도 할 수 있습니다. (샌드박스 모드는 다른 모듈에 영향을 주지 않고 모듈이 실행될 수 있는 환경을 제공하며, ).

let a = module.exports = "a";
로그인 후 복사

여기서 강조하고 싶은 점은

Node.js
    전역 변수가 여러 모듈에서 공유되므로 전역에서 속성을 정의하지 않도록 하세요. 데모의 정의는 이해를 돕기 위한 것입니다.
  • 같은 디렉토리에 global.a = 100;을 정의하는 1.js 파일이 있다고 가정해 보겠습니다. 이제 이 파일을 소개하므로(

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

    ) 현재 파일에서 변수 a를 정의하지 않고 두 모듈 파일을 함께 연결한다는 것을 알 수 있습니다. 위에서 언급한 내용은 노드의 전역 변수가 여러 모듈에서 공유된다는 것입니다.

    그 이유는

    Node
  • 환경에는 전역적으로 실행 컨텍스트가 있기 때문입니다.
  • // a.js
    var a = 100;
    module.exports = function(){}
    로그인 후 복사
    로그인 후 복사

    그래서 vm.runInThisContextglobal의 전역 변수에 액세스할 수 있지만 사용자 정의 변수에는 액세스할 수 없습니다. 그러나 vm.runInNewContext전역에 액세스할 수 없으며 사용자 정의 변수에도 액세스할 수 없습니다. 그리고 requirevm.runInThisContext를 통해 구현됩니다.

    🎜require 구현은 다음 네 단계로 나눌 수 있습니다. 🎜🎜🎜🎜가져와야 하는 파일을 읽어보세요. 🎜🎜🎜🎜파일을 읽은 후 코드를 함수로 캡슐화하세요. 🎜🎜🎜🎜 vm.runInThisContext를 통해 JS 구문으로 변환하세요. 🎜🎜🎜🎜코드콜. 🎜🎜🎜🎜이제 다음 두 파일이 있다고 가정합니다. 🎜a.js🎜 및 🎜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 将五个参数传入
    로그인 후 복사
    로그인 후 복사
    🎜입니다. 위의 4단계를 통해 가져오기 및 내보내기의 구현 로직을 분석할 수 있습니다. 🎜🎜🎜🎜🎜파일을 읽어보세요. 🎜🎜🎜수신해야 할 파일에 import해야 할 파일의 내용을 소개하면 이런 모습이 됩니다🎜rrreee🎜그런데 이 형태에서는 Node가 전혀 파싱을 할 수 없기 때문에 계속 진행해야 합니다. 두 번째 단계. 🎜🎜🎜🎜🎜읽은 파일을 함수로 캡슐화합니다. 🎜🎜
    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 教程!!

    위 내용은 Node.js의 VM 모듈에 대한 심층 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:juejin.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
최신 이슈
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿