nodejs for循环 常见问题_nodejs虚拟机

nodejs有一个叫vm的模块,这是用来运行代码的模块。

怎么说呢,我们知道浏览器只要你将代码放在script标签中,或script src远程引用它,代码就会执行,这些代码会执行一些我们没有定义但会预先传入的对象或方法,比如window, document, location, fetch等等。我们知道其实document, location, fetch这些东西都在window上,window是一个上下文。 在iframe中也有自己的window,各自独立。而在nodejs,怎么形成这个"window"呢,这就需要vm来提供。

nodejs有读取文件的能力 ,我们将一个index.js读出来,其实也只是一段文本,不会发生更大的用处。但是里面是我们的代码。要运行它们,以前我们知道用eval, new Function, 但它们不会明确指定一个上下文(eval根据调用的方式,会分为全局eval与局部eval)。

var globalVar = 11
eval('globalVar *= 2')
console.log(globalVar)

相对而言,new Function则比较麻烦

var globalVar = 11

console.log(globalVar)
var fn = new Function("globalVar", 'globalVar *= 2; return globalVar')
var a = fn(globalVar)
console.log(a) //22

new Function 是比较密封,数据太多就麻烦了。而eval则将外面的所有变量都寄及进去,太过evil。

但我们看到nodejs通过require也能运行其他模块啊。这是因为它们用到vm中的方法。

vm.runInContext(code, contextifiedObject[, options]),它相当于Function,第二个参数sandbox相当于Function的所有传参,当我们在函数価修改sandbox的成员,那么直接能在外面接收到。它必须与vm.createContext 一起使用。

const vm = require('vm');

const sandbox = {
 animal: 'cat',
 count: 2,
 globalVar: 99
};
vm.createContext(sandbox)

//必须传入第二个参数,sandbox或context
vm.runInContext('globalVar *= 2', sandbox);

console.log(sandbox)

76d52300a76b8814dd6dde3a4de87e46.png

vm.runInThisContext(code[, options]), 此方法不能指定上下文,因为它的上下文就是它当前所在的上下文。它里面的变量只能是外面的全局变量与方法,如console, process,global。

const vm = require('vm');

globalVar = 13 //全局的

vm.runInThisContext('globalVar *= 2;console.log("====")');

console.log(globalVar)

var aaa = 11;//本地

vm.runInThisContext('aaa *= 2');

console.log(aaa)

2095340255410ddd1a29331b416b6b14.png

在nodejs 9.10之前,module.js模块, require方法的实现就是使用 runInThisContext 来运行代码。

https://github.com/nodejs/node/blob/v9.10.0/lib/module.js#L613​github.com

vm.runInNewContext(code[, contextObject[, options]]) , 用法类似 runInContext,但是更加严格,只接受第二个对象传入的变量,外面的全局对象与方法一概不支持,连console.log也不行。

const vm = require('vm');

var sandbox = {
 globalVar: 11,
 filename: ""
}

//必须传入第二个参数,sandbox或context
vm.runInNewContext('globalVar *= 2; ', sandbox);
console.log(sandbox)

这是一个完美的沙箱。

vm.compileFunction(code[, params[, options]]), 这个除了最后一个参数,真的和new Function没什么两样。

最后解释一下options参数, 它有用的参数有几个:filename,当我们用fs.readFile(path)得到文本, 我们可以将path当作filename值,有利于我们跟踪错误; timeout, 指定执行时间,防止死循环这类特殊情况; contextName, 为上下文添加一个名字,方便调试.

另外,我们的代码也可以用 new vm.Script 包装起来,再执行上面的方法。

下面是一个性能分析,创建一个沙箱上下文是比较耗时,与 new Function没法比。

var vm = require('vm'),
    code = 'var square = n * n;',
    script = vm.createScript(code),
    sandbox;

n = 5;
sandbox = { n: n };

benchmark = function (title, funk) {
    var end, i, start;
    start = new Date;
    for (i = 0; i < 5000; i++) {
        funk();
    }
    end = new Date;
    console.log(title + ': ' + (end - start) + 'ms');
}

var ctx = vm.createContext(sandbox);
benchmark('vm.runInThisContext', function () { vm.runInThisContext(code); });
benchmark('vm.runInNewContext', function () { vm.runInNewContext(code, sandbox); });
benchmark('script.runInThisContext', function () { script.runInThisContext(); });
benchmark('script.runInNewContext', function () { script.runInNewContext(sandbox); });
benchmark('script.runInContext', function () { script.runInContext(ctx); });
benchmark('vm.compileFunction', function () { vm.compileFunction(code, ['n'])(n); });
benchmark('new Function', function () { new Function('n', code)(n); });

4384d7b9dcb9aef2a5dff649406b791a.png
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值