2.3.2 vm

vm的概念比较广泛,通常可以认为是硬件和二进制文件的中间层。在C++中,编译好的二进制文件可以直接被操作系统调用;而在Java中,编译好的字节码是交给虚拟机来运行的。这样的好处就是对开发者屏蔽了操作系统之间的差异,对于不同操作系统的处理交给了虚拟机来完成,从这个角度来看,vm是对不同计算机系统的一种抽象。

vm是Node的一个核心模块,vm可以使用V8的Virtual Machine Contexts动态地编译和执行代码,而代码的执行上下文是与当前进程隔离的,但是这里的隔离并不是绝对安全的,不完全等同于浏览器的沙箱环境。vm模块提供了一系列API用于在V8虚拟机环境中编译和运行代码。JavaScript代码可以被编译并立即运行,或编译、保存,然后运行。

【示例2-2】

    const util = require('util');
    const vm = require('vm');
    // 1. 创建一个 vm.Script 实例, 编译要执行的代码
    const script = new vm.Script('globalVar += 1; anotherGlobalVar = 1; ');
    // 2. 用于绑定到 context 的对象
    const sandbox = {globalVar: 1};
    // 3. 创建一个 context,并且把 sandbox对象绑定到这个环境, 作为全局对象
    const contextifiedSandbox = vm.createContext(sandbox);
    // 4. 运行上面编译的代码, context 是 contextifiedSandbox
    const result = script.runInContext(contextifiedSandbox);
    console.log('sandbox === contextifiedSandbox ? ${sandbox ===www.bsck.org
contextifiedSandbox}');
    // sandbox === contextifiedSandbox ? true
    console.log('sandbox: ${util.inspect(sandbox)}');
    // sandbox: { globalVar: 2, anotherGlobalVar: 1 }
    console.log('result: ${util.inspect(result)}');
    // result: 1

vm.Script是一个类,用于创建代码实例,后面可以多次运行。vm.createContext(sandbox)用于contextify一个对象,根据ECMAScript 2015语言规范,代码的执行需要一个execution context。这里的contextify就是把传进去的对象与V8的一个新的context进行关联。这里所说的关联是指contextified对象的属性将会成为context的全局属性,同时,在context下运行代码时产生的全局属性也会成为这个contextified对象的属性。

script.runInContext(contextifiedSandbox)就是使代码在contextifiedSandbox这个context中运行。从上面的输出可以看到,代码运行后,contextifiedSandbox中的属性的值已经被改变了,运行结果显示的是最后一个表达式的值。

除了上面几个接口之外,vm模块还有一些更便捷的接口,例如vm.runInContext(code,contextifiedSandbox[,www.90168.org options])、vm.runInNewContext(code[,sandbox][,options])等。