Function() 构造函数是否没有像 eval 那样被 V8 优化?
Is the Function() constructor not optimized by V8, like eval?
我们正在尝试一种通过 WebSockets 接收 Web 组件的方法。这些组件包含自定义脚本,它们应该在组件内部的上下文中 运行。
简而言之,我们有一些脚本字符串,想要 运行 它们。
现在我们正在为此使用 eval
,像这样:
function ctxEval(ctx, __script) {
eval(__script);
// return things with the ctx
}
并按预期工作,但我读到任何包含 eval
的函数都没有被 V8 优化。我想像这样将它转换为 new Function()
:
new Function("ctx", __script)(ctx);
这样我就可以实现和上面ctxEval
功能一样的效果了
我们知道Function
是eval()
,因为它们的作用几乎一样,但现在的问题是,到什么时候Function
才变成eval()
?可能是因为 Function()
有自己的作用域而不是 eval
作用域,运行 是同一作用域中的代码,包含 Function
调用的函数实际上由 V8 优化。此外,here 他们谈论 eval
但不谈论 Function
构造函数。
这个里面隐含的另一个问题是,运行里面的脚本Function()
是V8优化的吗?
我刚刚用这段代码测试了这个
const adder = new Function('a', 'b', 'return b%2 ? a + b : b%3 ? a - b : b%5 ? b / a : a * b');
let b = 0, b2 = 0;
function _throw() {
throw new Error('Ups');
}
function _catch() {
try {_throw()} catch(e) {}
}
function printStatus(fn) {
switch (%GetOptimizationStatus(fn)) {
case 1: console.log(fn.name, "function is optimized"); break;
case 2: console.log(fn.name, "function is not optimized"); break;
case 3: console.log(fn.name, "function is always optimized"); break;
case 4: console.log(fn.name, "function is never optimized"); break;
case 6: console.log(fn.name, "function is maybe deoptimized"); break;
}
}
eval('function evil(a,b) {return b%2 ? a + b : b%3 ? a - b : b%5 ? b / a : a * b}');
printStatus(adder);
printStatus(evil);
printStatus(_throw);
printStatus(_catch);
// Call the function
for(let i = 0; i < 2000; i++) {
b = adder(Math.random() * 10, b);
b2 = evil(i, b2);
_catch();
}
printStatus(adder);
printStatus(evil);
printStatus(_throw);
printStatus(_catch);
运行 命令
$ node --allow-natives-syntax js.js
输出为
anonymous function is not optimized
evil function is not optimized
_throw function is not optimized
_catch function is not optimized
anonymous function is optimized
evil function is optimized
_throw function is not optimized
_catch function is not optimized
编辑:
我修改了这个测试代码来检查其他的 bailot,我真的很惊讶,因为看起来 eval
也被优化了 :>
编辑 2:
经过一些额外的研究,我发现了这个 https://blog.sqreen.io/optimize-your-node-app-by-simply-upgrading-node-js/
我们正在尝试一种通过 WebSockets 接收 Web 组件的方法。这些组件包含自定义脚本,它们应该在组件内部的上下文中 运行。
简而言之,我们有一些脚本字符串,想要 运行 它们。
现在我们正在为此使用 eval
,像这样:
function ctxEval(ctx, __script) {
eval(__script);
// return things with the ctx
}
并按预期工作,但我读到任何包含 eval
的函数都没有被 V8 优化。我想像这样将它转换为 new Function()
:
new Function("ctx", __script)(ctx);
这样我就可以实现和上面ctxEval
功能一样的效果了
我们知道Function
是eval()
,因为它们的作用几乎一样,但现在的问题是,到什么时候Function
才变成eval()
?可能是因为 Function()
有自己的作用域而不是 eval
作用域,运行 是同一作用域中的代码,包含 Function
调用的函数实际上由 V8 优化。此外,here 他们谈论 eval
但不谈论 Function
构造函数。
这个里面隐含的另一个问题是,运行里面的脚本Function()
是V8优化的吗?
我刚刚用这段代码测试了这个
const adder = new Function('a', 'b', 'return b%2 ? a + b : b%3 ? a - b : b%5 ? b / a : a * b');
let b = 0, b2 = 0;
function _throw() {
throw new Error('Ups');
}
function _catch() {
try {_throw()} catch(e) {}
}
function printStatus(fn) {
switch (%GetOptimizationStatus(fn)) {
case 1: console.log(fn.name, "function is optimized"); break;
case 2: console.log(fn.name, "function is not optimized"); break;
case 3: console.log(fn.name, "function is always optimized"); break;
case 4: console.log(fn.name, "function is never optimized"); break;
case 6: console.log(fn.name, "function is maybe deoptimized"); break;
}
}
eval('function evil(a,b) {return b%2 ? a + b : b%3 ? a - b : b%5 ? b / a : a * b}');
printStatus(adder);
printStatus(evil);
printStatus(_throw);
printStatus(_catch);
// Call the function
for(let i = 0; i < 2000; i++) {
b = adder(Math.random() * 10, b);
b2 = evil(i, b2);
_catch();
}
printStatus(adder);
printStatus(evil);
printStatus(_throw);
printStatus(_catch);
运行 命令
$ node --allow-natives-syntax js.js
输出为
anonymous function is not optimized
evil function is not optimized
_throw function is not optimized
_catch function is not optimized
anonymous function is optimized
evil function is optimized
_throw function is not optimized
_catch function is not optimized
编辑:
我修改了这个测试代码来检查其他的 bailot,我真的很惊讶,因为看起来 eval
也被优化了 :>
编辑 2:
经过一些额外的研究,我发现了这个 https://blog.sqreen.io/optimize-your-node-app-by-simply-upgrading-node-js/