Hello World
Spiga

由eval生成的代码效率真的很差吗?

2012-08-15 21:29 by 老赵, 14021 visits

昨晚跟一位Node.js专家讲解了我的Wind.js类库。之前那位仁兄对Jscex(Wind.js的前身)的看法是“就是不喜欢”,也在微博上对Jscex冷嘲热讽,于是我私信他说建议看一下文档了解一下Jscex。昨天我们的争论主要围绕在eval的使用上,他认为更好的做法是像CoffeeScript那样使用一个额外的进程监听改变,这样更方便。我说CoffeeScript这么做是因为它没有像Wind.js那样借助eval实现完全动态的运行时转化,且生产环境中不会出现eval。最后他坚持认为“eval就是有性能问题”,因此开发时也不应该使用,否则Wind.js为什么要提供预编译器?虽然最后不欢而散,不过我忽然也打算验证一下eval生成的代码效率到底会差到什么样的地步,于是便有了这次试验。

测试代码

有人可能会问,eval每次动态的执行代码时需要重新分析代码,还不能进行优化,为什么会“不慢”?不过请注意,这里测试的目标不是用eval执行代码慢不慢,而是反复执行通过eval生成的代码,因为这才是Wind.js对eval的使用方式。Wind.js中每次eval将会生成一个函数,然后在使用的过程中不会反复eval

既然是测试纯性能,我就找了个纯粹用来计算的函数:LCG随机数生成器。这个随机数生成器实现简单,效率极高,因此运用十分广泛。这里我们不关心它的原理,只给出它的JavaScript实现:

var nativeRandomLCG = function (seed) {
    return function () {
        seed = (214013 * seed + 2531011) % 0x100000000;
        return seed * (1.0 / 4294967296.0);
    };
};

var evalRandomLCG = function (seed) {
    var randomLCG = eval("(" + nativeRandomLCG.toString() + ")");
    return randomLCG(seed);
};

nativeRandomLCG将通过seed生成一个随机数生成器,而evalRandomLCG则会将前者的代码作为字符串取出,并在eval后重新获得随机数生成器。我们的评测对象便是这两个生成器:

var nativeSuite = {
    name: "native",
    target: nativeRandomLCG(100)
};

var evalSuite = {
    name: "eval",
    target: evalRandomLCG(100)
};

var iterations = [100, 200, 300];

for (var round = 0; round < iterations.length; round++) {
    console.log("Round " + round);
    test(iterations[round] * 1000 * 1000, nativeSuite, evalSuite);
    console.log("");
}

我将进行三轮测试,分别生成100M,200M及300M个随机数,并观察两个随机数生成器的耗时。完整代码可以在此获得,其中lcg.js可以直接作为Node.js程序运行,而lcg.html则可以在浏览器里打开,点击页面上的按钮启动计算,测试结果会在控制台里输出。

由于Node.js可以在不同平台上使用,而Windows和OSX又各有一个不跨平台的浏览器,因此我会在两个平台上分别对Node.js和主流浏览器进行测试。为了避免Firefox出现“脚本执行时间过长,是否中止”这样的提示,还需要对其进行简单的设置

Windows实验结果

Windows上的实验使用的是我工作时所使用的ThinkPad 520,操作系统为Windows 7,CPU信息如下:

ThinkPad 520 CPU

四个JavaScript执行环境为:

  1. Node.js 0.8.6
  2. IE 9
  3. Chrome 21
  4. Firefox 14

实验结果:

图表:

从中我们可以清晰地得出:

对于Node.js来说,使用eval得到的函数,其执行效率和JavaScript直接定义的函数可谓毫无二至。事实上,除了IE似乎eval普遍稍慢于原生函数外,其他引擎里的表现都可谓基本持平,连IE的落后也基本可以忽略不计。所以,“eval出来的代码效率会有很大差距”这种说法,至少在这个实验中丝毫没有体现出来。

有意思的是,在Chrome中还发生了这么一件事情:在第一轮比较中,原生定义的函数有较大的性能优势,而且自从测试了eval得到的函数之后,后面两轮连原生函数的效率都下降了。这会不会是因为eval让整个执行引擎大打折扣了呢?严谨起见,我又测试了三种情况:

  • 两个测试用例都使用原生函数。
  • eval得到的函数先于原生函数前执行。
  • 两个测试都使用eval得到的函数。

都得到了类似的结果:先执行的函数效率会高出许多。我猜测这是因为Chrome发现了大量的密集计算,为了保证界面的响应能力,将JavaScript执行的优先级降低的缘故。值得一提的是,尽管Chrome的“降速”后的结果略慢于IE和Firefox,但它是唯一一个在性能测试的时候,整个界面还没有失去响应的浏览器。此时我可以切换到其他Tab,也可以关闭这张页面——甚至控制台里输出的文字也是立即出现的,而其他两个浏览器都必须等整段程序执行完成之后所有输出才同时出现。

必须承认,Chrome浏览器在这方面的确可圈可点。

OSX实验结果

OSX上的实验使用的是一台高配的MBP with Retina Display,操作系统为最新的OSX Mountain Lion,CPU信息如下:

四个JavaScript执行环境为:

  1. Node.js 0.8.0
  2. Safari 6
  3. Chrome 21
  4. Firefox 14

实验结果:

图表:

由于结论十分类似,我就不多做分析了。不过有意思的是,不知为何Safari浏览器的性能极低,我一开始使用相同规模的实验数据,发现Safari迟迟不返回结果,直到我将生成随机数的数量降低到十分之一时,才得到Safari如今的耗时。因此请注意这里的Safari附带的x0.1字样,正是指它实验数据的规模仅仅为其他JavaScript执行引擎的十分之一。

总结

eval本身的执行无疑会慢,因为它需要动态的分析那段字符串的内容才能执行,且单次执行为它进行优化可能也得不偿失。但是,像Wind.js那样将eval的结果反复执行,并非反复执行eval本身,这可能就是另外一回事情了。eval最终还是得到一段代码,而这段代码在反复执行过程中可能也会被JIT,也会被优化。

我不能说我设计的这个简单案例就能说明一切,但是至少通过这个我立即就想到的首个测试用例,能够说明eval的某些使用方式可能并不想许多人幻想中对性能会产生多大的影响。而且对于Wind.js这种异步类库来说,程序几乎都是在等待异步任务完成,代码层面的性能基本不会造成任何影响。如果你实在害怕eval,完全可以在生产环境中通过预编译消除所有的eval。这里的预编译并不是为了性能,而是让代码可以脱离体积最大的编译器模块运行,剩下的部分在Minified和GZipped之后只有4K大小。

如果你非要如那位Node.js专家说“eval就是慢”,那我只能这么说:

在Wind.js中使用eval不会产生什么性能问题,我觉得排斥的人有三种情况:不熟悉eval,不熟悉是不了解Wind.js,找茬。

我在微博上说了上面这句话之后,却得到那位专家这样的回应:

看來,不喜歡Wind.js的人要麼是不懂,要麼是故意找茬了。Wind.js是不容置疑的。//@老赵 :我觉得排斥的人有三种情况:不熟悉eval,不熟悉Wind.js,找茬……

我顿时觉得很生气,说道:

身为有头有脸的专家不要断章取义,我说的是排斥“Wind.js里使用eval”。你可以不喜欢Wind.js,但是要说出靠谱的理由。上次你也跑上来黑一票Wind.js就走,真枉我买过你的书。

结果却得到对方“义正词严”的批评:

還是請您就事論事,不要人身攻擊。

真令人好生疑惑,我这就算是人身攻击?哪里没有就事论事?是谁在断章取义,搞低级黑?

那攻击就攻击吧,反正我已经很失望了。

注:也有实验显示eval对性能的影响,并非要用过eval执行,或是执行eval出的代码才能体现出来,而eval某些存在方式也会让JavaScript引擎降低对其他代码的优化程度。因此,Wind.js中的eval到底产生多大影响也需要做进一步探明。接下来我也会在Wind.js官方网站上发布一些更针对Wind.js中eval使用方式的性能测试报告。

Creative Commons License

本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名赵劼(包含链接),具体操作方式可参考此处。如您有任何疑问或者授权方面的协商,请给我留言

Add your comment

53 条回复

  1. 链接

    Paul 2012-08-15 21:40:17

    Excel Web App 的图很赞

  2. Elementstorm
    111.161.23.*
    链接

    Elementstorm 2012-08-15 21:42:55

    共党说过:没有调查就没有发言权 最喜欢看用证据甩人脸了~~~

  3. 链接

    ayanamist 2012-08-15 22:20:17

    另外一个当事人是byvoid

  4. 老赵
    admin
    链接

    老赵 2012-08-15 23:04:50

    @ayanamist

    好吧,我故意不说出来给人面子的。

  5. zaeneas
    219.140.201.*
    链接

    zaeneas 2012-08-15 23:24:23

    我觉得微博的字数限制不适合讨论任何问题,当然技术问题也包含在内

  6. nfang
    58.161.130.*
    链接

    nfang 2012-08-16 07:18:26

    "Eval is overwhelmingly trivailised, misused, and outright condemned by most JavaScript programmers but by looking at the work of some of the best coders you can see that, when used appropriately, it allows for the creation of some fantastic pieces of code that wouldn’t be possible otherwise." -- John Resig

  7. 老赵
    admin
    链接

    老赵 2012-08-16 09:03:25

    @zaeneas

    讨论的请不清楚,跟有没有好好讨论,是不是低级黑,是不是冷嘲热讽还是分得清的。

  8. 菜鸟
    222.55.42.*
    链接

    菜鸟 2012-08-16 09:09:31

    eval绑定执行函数确实有性能的影响 但wind.js的控制十分到位,正如老赵的为人品格一样,刚正不失儒雅

    支持老赵,也希望老赵把wind.js发扬广大

  9. xiaop
    202.95.122.*
    链接

    xiaop 2012-08-16 09:36:24

    大多数人都会基于常识和以往的知识储备进行判断,这个也是很正常的吧。 所以,沟通的时候找到隔阂点往往就很容易解决了。

    当然,执着于自己的看法听不进去意见的人也不少

  10. rhapsodyn
    113.108.76.*
    链接

    rhapsodyn 2012-08-16 09:50:36

    打脸什么的最喜欢了

  11. liexusong
    58.255.253.*
    链接

    liexusong 2012-08-16 12:19:50

    JavaScript是怎么编译的我不是很懂,不过对于同样是动态语言的PHP来说,eval会导致切换编译上下文,所以总的来说eval会比原生的代码慢一些,但是影响应该不会很大。对于JavaScript这种运行于客户端的脚步来说,eval还没有什么危害,不过对于服务端脚步来说,eval就是一个噩梦。

  12. 老赵
    admin
    链接

    老赵 2012-08-16 13:27:09

    @liexusong

    说说看怎么个恶梦法,根据我的实验看不出差别么。

  13. Jerry Bian
    58.240.218.*
    链接

    Jerry Bian 2012-08-16 15:49:19

    有理有据,方能服人。支持老赵。

  14. Cat Chen
    216.157.85.*
    链接

    Cat Chen 2012-08-18 12:49:23

    合理的测试方法是把测试代码放到 jsperf 上让所有人来帮你测。个别机器个别浏览器的测试结果没有意思。

  15. Cat Chen
    216.157.85.*
    链接

    Cat Chen 2012-08-18 12:55:10

    之所以让你用 Benchmark.js 和 jsperf,是因为它们已经解决了如何正确 benchmark 的问题。你这样自己跑数据,别人同样可以质疑你方差多少,置信度多少。(发现 benchmark 也是个坑了吧。)

  16. gsralex
    115.58.249.*
    链接

    gsralex 2012-08-18 18:36:24

    最近总是js吗?看不大懂诶

  17. 老赵
    admin
    链接

    老赵 2012-08-19 00:06:25

    @Cat Chen

    我倒不觉得,反正我的实验代码都是公开的,有人质疑的话随意下载自行尝试我毫无意见,没有放到jsperf上也就是个方便程度的问题。下次我还是会这么测的,毕竟还要跑Node.js,不如统统自己写了。如果不需要测试Node.js,我可能会考虑(额外)放一份到jsperf上去。

  18. 老赵
    admin
    链接

    老赵 2012-08-19 00:10:43

    @gsralex

    毕竟在搞Wind.js么……其实.NET也积攒了近10篇标题,其中一篇甚至是个至少5、6篇的系列……

  19. shell
    222.68.177.*
    链接

    shell 2012-08-20 14:54:45

    Opera也不会卡死。而且执行效率比Chrome快很多。。

  20. Simon
    123.126.29.*
    链接

    Simon 2012-08-20 16:20:32

    The 'eval' method, and related constructs such as 'new Function', are extremely wasteful. They effectively require the browser to create an entirely new scripting environment (just like creating a new web page), import all variables from the current scope, execute the script, collect the garbage, and export the variables back into the original environment. Additionally, the code cannot be cached for optimisation purposes. eval and its relatives should be avoided if at all possible.

  21. acao
    121.15.58.*
    链接

    acao 2012-08-20 17:42:10

    当初看了github上面的demo,全是evel实现的,我也在想找个问题,今天老赵给了说明就豁然了 之前的名字怎么突然改了?

  22. 老赵
    admin
    链接

    老赵 2012-08-20 22:59:02

    @Simon

    这谁都知道,套话而已,用得合不合适具体问题具体分析。

  23. 老赵
    admin
    链接

    老赵 2012-08-20 22:59:34

    @acao

    其实这里没有说明为什么用eval,只是说明了用eval没有问题。

  24. october
    113.110.148.*
    链接

    october 2012-08-21 00:26:12

    eval并没有什么性能损失吧. eval只是可以让程序员人为控制编译时机, 但编译消耗的时间还是一样的. 比如某一js文件有10000行代码, 假设需要编译x秒 把后5000行代码用eval包起来后,

    js文件:

    ... 此处5000行js代码 ...
    eval("...此处5000行js代码...")
    

    那么过程就变成了: 编译前5000行 -> 运行前5000行 -> 运行到eval() -> 编译后5000行

    看的出来,只是编译人为置后了, 应该没有性能损失....拙见....

  25. boringame
    121.207.68.*
    链接

    boringame 2012-08-21 06:42:50

    我冒昧的给wind.js简化了语法,并且测试了可行性。

    var showAsync = eval(Wind.compile("async", function (msg) {
        $await(sleep(1000));
        alert(msg);
    }));
    
    showAsync('hello').start();
    

    相比回调函数方式,wind.js太赞了。但是eval(Wind.compile("async",function(){})这个外壳还能简化一点:

    var show = function (msg) {
        $def($async);
    
        $await || sleep(1000); 
        alert(msg);
    };
    
    show.newTask('hello').start();
    

    做的改动,这些改动全部符合js语法,但是定义了新的语义: 使用$def($async),代替compile('async',)第一个参数,语义上可以理解为Attribute。 去掉显示的eval(并且解决闭包问题); 修改使用task模型的方式,show()是原函数,show.newTask()是异步task,方便测试。 $await(task)变成了:$await || action(),语义上理解为“等待或直接执行”。

    可行性实验:

    Function.prototype.newTask = function () {
        //$def解决eval闭包
        try {
            $def = eval;
            $async = 'throw ' + 生成的函数语句;
            show();
        } catch (生成的函数) {
            this.newTask = 生成的函数;
            return this.newTask(arguments);
        } finally {
            $def = function () { };
            $async = 'async';
            /*让$def在实际执行过程中无用*/
        }
    }
    

    只要简单修改调用方式,就能调试了。 show()执行原函数,可调式;show.newTask().start()执行异步。 直接执行$await || sleep(1000)时,$awaitfalse,所以执行sleep(1000);,异步编译成:$binder.Bind(sleep.newTask(1000),...);

    或者使用一个全局设置是否启用调试,如果启用调试的话,在newTask的时候,直接伪装一个Task

    Function.prototype.newTask = function(){
        if (启动调试) {
            this(args);
            return { start : function(){/*伪装而已*/}};
        }
        ...
    }
    

    阻止了所有编译,程序中所有的异步调用如,show.newTask().start() 都不必更改代码,就可调式。其实不用改成“||”语法的,只是我讨厌嵌套括号。

    可能出现的新问题和不完善的办法:

    某些异步操作无法阻塞执行(如sleep),无法在同步调试过程中起作用。解决:如果非调试时使用同步方式调用,提示无法同步调用的异常。

    sleep = function () {
        if (!调试) throw;
    };
    
    sleep.newTask = function () {
        return Wind.Async.sleep();
    }
    

    this指向问题,obj.func.newTask() 这种调用方式会导致this无法指向obj。解决:obj.func.newTask.call(async,args);obj.asyncFunc = function(){}.asAsync();

    如果同步方法作为obj.func,异步就要.call(this,args),反之也一样,让用户自己选吧,我call。

    在多线程环境执行$def(code)定义,可能出现错乱。解决:没有lock(),用while(locakToken);来降低冲突概率,还有乐观锁也能降低些概率。但是终归是没想出一个比较完善的方案,不知道有没有这方面的算法。好在我们通常在浏览器启动的单线程环境初始化,node.js我不了解。

  26. 老赵
    admin
    链接

    老赵 2012-08-21 08:33:59

    @boringame

    这想法有意思的,但是变的太复杂了,而且有个前提:“eval能够改名成$def”,但如果这个条件成立的话,就直接$def(Wind.compile(...))就行了,干嘛这么绕啊……

    还有一直不明白你说的“可调试”是什么意思……为什么需要调试编译前的代码?编译后的代码为什么不可调试了呢?

  27. boringame
    121.207.68.*
    链接

    boringame 2012-08-21 15:31:18

    个人愚见,语法更美观,不用嵌套n个括号。

    var func = function (msg) {
        $def($async);
    };
    

    原版:

    var asyncFunc = $def(Wind.compile('async', function () {
    
    }));
    

    感觉也语义化:

    function () { 标记为(异步的) },
    执行(Wind.编译('异步',原来的函数))。
    

    调试问题:编译前的方法可以直接源代码打断点呀。

    我做了个demo,验证$def=eval可行,并且认为简化了使用wind.js。

    排序的的例子:

    var swap = function (array, i, j) { $def($async);
        var t = array[i];
        array[i] = array[j];
        array[j] = t;
        paint(array, [i, j]);
        $await || sleep(1000);
    };
    
    var bubble = function(arrary){ $def($async); 
        for (var i = 0; i < array.length; i++) {
            for (var j = 0; j < array.length - i - 1; j++) {
                if (array[j] > array[j + 1])
                    $await || swap(array, j, j + 1);
            }
        }
    }
    
    bubble.newTask([1,2,3,4,5]).start();//使用异步排序
    bubble([1,2,3,4,5]); //同时还可以直接调用原版也很方便
    

    意图让人忘记wind.js的存在。。。

  28. 老赵
    admin
    链接

    老赵 2012-08-22 11:22:28

    @boringame

    挺有意思的思路呵呵,这种写法可以考虑一下。不过前提还是eval可以取别名,似乎是有限制的啊,我去了解下。还有使用起来不方便了,要newTask,要知道方法定义是一次性的,使用是反复多次的啊,你让一次操作变得好看一下,但是反复的操作变得麻烦了……

    还有直接调试原版没这需求吧,所有异步操作都没用了,而且用户绑定其他异步操作时也写两套吗?

  29. boringame
    121.207.68.*
    链接

    boringame 2012-08-22 13:49:58

    eval是不是有什么特殊限制?小弟在井底,求指点。

    某些情况下,调试原版是有用处的,比如上面的排序方法。 异步函数和同步函数,逻辑上基本无差别, 所以我相信很多情况下,调试原版能够很多问题。

    我不认为这样的转换会成为负担,由于原来也需要.start(): asyncFunc(pars).start(); func.newTask(pars); 通常也只有入口这样写,异步中:$await || func(pars)。

    “而且用户绑定其他异步操作时也写两套吗?”没太懂意思?

  30. 老赵
    admin
    链接

    老赵 2012-08-22 22:02:40

    @boringame

    我记得eval的一个限制就是不能取别名。

    调试原版没多大意义的,每个异步操作都得不到结果,似乎除了sleep这种除了耗时没有任何限制的操作才有调试原版的意义。

    最后那个“入口”我还是倾向于不要有两种不同的方式,希望方法就是普通的使用方法,不要多一种newTask来……

    现在你的改进其实只是皮毛上一点区别,也没给使用方便程度上带来特别的好处,满足的只是一些说不清道不明的品味,优先级就放低吧……

  31. boringame
    122.90.217.*
    链接

    boringame 2012-08-23 00:53:46

    嗯,是的,这些和核心没关系,一点点语法糖。

    调试原版无意义我觉得还是要再思考一下。 除了sleep,还有很多是可以调试的。 除了需要用户输入的东西,如click, 很多可变为同步执行,如ajax。

    也可能只是我的个人需求,总归您当是用户反馈把。 希望wind.js的核心越来越给力。

  32. 老赵
    admin
    链接

    老赵 2012-08-23 09:43:33

    @boringame

    嗯嗯,多谢建议。那个AJAX操作往往是在请求数据啊,你在“调试原版”时返回什么数据呢?用户点击也是要返回点击信息的。而且话说回来,异步方法又不是不能调试,为什么要调试原版呢?

  33. boringame
    122.90.217.*
    链接

    boringame 2012-08-24 00:08:10

    httpReq 有一个"是否同步"的参数async可以设置。不是一定要异步的,同步执行的返回结果是一样的。

    httpReq.async = false;
    httpReq.callback = function (value) {
    
    }
    
    httpReq.post(url);
    

    异步方法的调试还真知道怎么弄搞,麻烦给个url赐教一下把。设置断点这样的VS支持的功能,也能做到吗?

  34. 老赵
    admin
    链接

    老赵 2012-08-24 08:40:51

    @boringame

    我只是用AJAX举个例子,这样的例子多了,比如动画播放,用户交互都是异步,Node.js里面呢?几乎没有异步操作可以同步完成的。

    异步方法的调试我有空了写篇文章吧……

  35. test
    1.202.240.*
    链接

    test 2012-08-25 08:45:12

    我觉得这个测试有问题。

    直觉上,感觉复用eval生成后的代码效率不会太差,滥用eval主要性能损失主要是在执行eval,生成代码的过程中吧,在真正的代码实践中,会不会有程序员每次都去重新eval一遍呢?我觉得你和那个node.js专家鸡同鸭讲了。

    PS,比如光测试一亿次整形运算,java可能比c++还快一样,并不能说明生产实践中java比c++快,不能割裂的看待问题。

  36. 老赵
    admin
    链接

    老赵 2012-08-25 23:38:28

    @test

    测试没问题,你说的eval这种用法性能差谁都知道,试都不用试。使用时不会每次都eval,我测试的是Wind.js里的使用方式,我跟那位专家也强调了很多次。

    看我最后一句话:“要么不熟悉eval,要么不了解Wind.js”。

  37. 我的温柔
    77.13.182.*
    链接

    我的温柔 2012-08-28 06:08:04

    在服务器端使用eval会不会产生安全问题?毕竟eval可以用来注入代码。

  38. 老赵
    admin
    链接

    老赵 2012-08-28 09:48:08

    @我的温柔

    给个Wind.js中注入的情况看看?不是每种用法都能注入的。

  39. ghostheaven
    134.134.139.*
    链接

    ghostheaven 2012-09-11 13:08:34

    其实主要是eval里面返回的是一个函数,类似 eval('function(){...}') 这样,运行的时候执行的是这个函数,理应没有什么性能损失。

  40. cathy
    24.59.95.*
    链接

    cathy 2012-10-24 06:02:56

    测试一下我的评论

  41. rockyoung
    202.107.194.*
    链接

    rockyoung 2012-12-03 11:18:30

    呵呵,赵哥,你这是何必呢,“喜不喜欢”这东西是不需要什么理由和原因的,你越想让他喜欢或不讨厌,他心里也许越抵触

  42. 老赵
    admin
    链接

    老赵 2012-12-03 14:32:25

    @rockyoung

    你是小白的话我无所谓,你能影响的人越多,我不在意的话吃亏的就是我自己。

  43. bink
    116.90.82.*
    链接

    bink 2013-04-02 10:51:35

    好恐怖,你这样测试意思难道是会有谁去运行n次eval? 谁不是在无可奈何下采用一次eval。所以你eval后运行千儿八百次也没啥意义。 你不重复的使用eval,难道别人重复的使用eval了? 扯哪去了这是。这测试一点点的意义都没有。 其实后面的两个人对话都是挺冲的。。。。。。半斤八两。给人有点小心眼的感觉。 不像是学术讨论

  44. bink
    116.90.82.*
    链接

    bink 2013-04-02 10:52:27

    不过其他的文章我还是很喜欢的,就是这篇不喜欢~~

  45. 老赵
    admin
    链接

    老赵 2013-04-02 17:37:26

    @bink

    是没有意义,关注eval的性能本身就没有意义,是有人非说eval慢,于是我测给你看慢不慢。

    这种东西根本就不是学术讨论,而是低级的FUD,所以我也不会给好脸色看。

  46. pink
    116.90.82.*
    链接

    pink 2013-04-07 13:05:30

    哈 说的也是。而且在10000的成绩上去找那1的瑕疵本身就有毛病

  47. xy2401
    125.77.3.*
    链接

    xy2401 2013-06-19 14:57:19

    好高端,留著以後慢慢看,我現在就只有使用他一個方法

    this.type = type;
    
        var temp1 = "";
        var temp2 = "";
    
        if(type == "h"){
            temp1 = "hw";
            temp2 = "Hw";
        }else if(type == "s"){
            temp1 = "sw";
            temp2 = "Sw";
        }else if(type == "i"){
            temp1 = "iisi";
            temp2 = "Iisi";
        }else if(type == "serv"){
            temp1 = "serv";
            temp2 = "Serv";
        }
    
        //costRate = hwCostRate;
        costRate = eval( temp1 + "CostRate"); //獲取變量 hwCostRate或者swCostRate 等
        cost = eval( temp1 + "Cost");
        income = eval( temp1 + "Income");
        profit =  eval( temp1 + "Profit");
    

    就是用costRate = hwCostRate。這樣省掉大段重複if else 賦值。 不知道是否有性能的問題

  48. maquan
    58.246.216.*
    链接

    maquan 2014-03-25 15:30:39

    虽然没有做过测试,但我认为,“有人可能会问,eval每次动态的执行代码时需要重新分析代码,还不能进行优化,为什么会“不慢”?”,这话对,但却是一句废话,因为javacript作为动态语言,没有编译过程,所有的语句都是一句一句动态执行的,即使不用eval也是动态的。这个java不一样,java做了动态反射以后语句由静态转为动态,当然效率低了,javascript却是全动态,用了eval是动态的,难道不用eval的语句就是“静态”执行的了?所以我不认为eval会因为“动态分析代码”造成效率问题,即使效率真的差了,也绝不是因为“动态”造成的。 没有自己测过,但我觉得老赵的测试是对的,专家在胡扯,其实很多时候要写eval这样的函数多数是万不得已,没人会闲着没事干给自己找点茬留个注入漏洞去用eval. 新人刚学Javascript不到一个月,说错了请见谅哈

  49. 老赵
    admin
    链接

    老赵 2014-03-25 23:24:31

    @maquan

    的确是错了啊,哈哈……

  50. maquan
    180.169.135.*
    链接

    maquan 2014-03-26 09:34:16

    错了啊,那我继续研究去。。。。

  51. John Wu
    180.160.38.*
    链接

    John Wu 2014-04-08 06:24:42

    我个人认为这个结论还是下得太过草率了。你只进行了一次对比,但是并没有考虑到函数体大小、涉及的外部变量等这些问题。光就这个实验而言得出这个结论,我个人而言不信服。

  52. doop
    183.49.123.*
    链接

    doop 2014-07-01 19:46:34

    我的代码里面有些 地方也用eval

    确实能解决很多问题 比如动态的 实名函数 如果说性能 还真没发现什么问题

  53. clark
    171.214.250.*
    链接

    clark 2015-09-28 22:19:15

    有一些服务器脚本,可以预处理成中间码,这样的话,类似eval这种情况肯定性能就会有所降低了

发表回复

登录 / 登录并记住我 ,登陆后便可删除或修改已发表的评论 (请注意保留评论内容)

昵称:(必填)

邮箱:(必填,仅用于Gavatar

主页:(可选)

评论内容(大于5个字符):

  1. Your Name yyyy-MM-dd HH:mm:ss

使用Live Messenger联系我