包含<script>标签与使用eval?</script>相比,是否有性能提升?

时间:2011-12-05 01:48:26

标签: javascript performance eval

我已经看到很多关于如何动态添加代码的建议,如(source)

var myScript = document.createElement("script");
myScript.setAttribute("type","text/javascript");
myScript.innerHTML += 'alert("Hello");';
document.body.appendChild(myScript);

eval相似

eval('alert("Hello");');

人们抱怨eval的性能下降和安全问题,但我无法想象添加<script>标签会更快或更安全。


编辑人们想知道为什么我正在评估与alert("Hello")一样微不足道的事情,原因如下:

我有一个数据库,比方说,1,000,000,000,000个脚本= P显然我不能加载每一个,而是用户可以加载他们想要的任何一个。脚本存储在服务器端的arbritrary位置。目前我通过其脚本名称请求(xmlhttprequest被解释为javascript)脚本,服务器将以某种方式找到它并将其作为文本返回,立即执行/解释。我想知道将脚本作为文本返回是否更好,然后从中创建一个<script>标记。

此外,这不是Javascript difference between eval() and appending script tags的副本,它处理功能差异,这里我想要性能和安全性差异。

5 个答案:

答案 0 :(得分:7)

不,使用<script>代码与使用eval相比,没有任何性能提升。在您提供的两个示例中,eval在我测试的所有浏览器中都要快得多。部分不同之处在于使用<script>,除了运行脚本之外,它还在修改DOM,但并不是全部。使用较长的脚本时,差异并不明显,但eval仍然更快:

更新:我更新了演示,以便更好地匹配测试(两者现在都在创建script块)。结果仍然显示eval要快得多。

jsPerf:http://jsperf.com/stackoverflow-8380204-eval-vs-script

enter image description here

因此,不使用eval的原因仅与安全相关。来自Why is using the JavaScript eval function a bad idea?上接受的答案:

  
      
  1. 不当使用eval会打开您的注射攻击代码
  2.   
  3. 调试可能更具挑战性(没有行号等)
  4.   

还有第三个谈论速度,但在答案的评论中反驳了。如果您无法保证计划eval的脚本来源,则应避免使用。

暂且不说:根据问题末尾的使用模式,您可能需要查看require.js以动态加载脚本。

答案 1 :(得分:2)

这可能是基于浏览器和程序员自己的观点而改变的辩论之一。我不认为这两种方法之间有任何明显的性能差异,除非你多次做这种事情(即便如此,这可能是设计问题的指示)。

只是旁注;传递给eval()的代码可能特别难以调试,并且无法以异步加载JavaScript的方式缓存:

(function() {
    var s = document.createElement('script');
    s.async = true; // HTML5
    s.type = 'text/javascript';
    s.src = 'http://example.com/application.js';
    var x = document.getElementsByTagName('script')[0];
    x.parentNode.insertBefore(s, x);
    // can be added to the body element as well, which may be better.
})();

请注意,这与您的代码不同,因为它会从服务器加载脚本,而不是直接将Javascript写入元素。老实说,我无法想象当你可以远程加载文件时为什么要这样做。

答案 2 :(得分:2)

你确实意识到你做了两件不同的事情。

“eval” - &gt;启动JS解释器,解释并运行js代码。

“script” - &gt;获取DOM构造并注入脚本节点,然后启动JS解释器,解释并运行js代码。

基本上浏览器和eval一样。您只需要在DOM中创建和注入节点的开销

答案 3 :(得分:0)

我认为eval更好,因为如果您创建一个新元素并将其写入正文的末尾,浏览器永远不会在脚本标记存在时释放此内存,这将以某种方式影响一般性能。

在eval的情况下,解析和执行的速度(可能)等于解析的新脚本标记,传递的字符串可能会在完成后从内存中释放。

至于安全性,我认为它可能包含您的eval中的恶意代码,您也可以将其包含在脚本标记中。

无论如何,正如@jergason所说,避免两者同样糟糕。

答案 4 :(得分:0)

我在尝试解决类似问题时偶然发现了这个对话。

很多评论质疑OP的动机是什么,这是有效的。

我的用例解决了这个需求......我想从服务器加载JS代码,但它不是http服务器。客户端(浏览器)通过websocket连接并同步到服务器端DOM之类的东西。

但是服务器DOM的节点可能希望向用户发出JavaScript代码以操纵这些节点。该代码想要通过websocket,但问题是如何将它注入浏览器。

这些代码片段也可能有依赖关系,因此我为require.js编写了一个websocket插件来满足它们....某些部分可能是通过httpd提供的静态文件,但其他部分可能是基于动态生成的在用户ACL上。

所以......从这个线程中仍然不清楚注入浏览器的最佳方式。有人认为eval()是可以的,但是使用innerText添加脚本标签是另一种方式。另一个想法是b64编码脚本标记的src值。

网上有人提到,动态注入的代码不会受益于v8中的某些代码优化,并且会严重损失性能。一个基本的警报(&#39; hello world&#39;);&#34;可能不会透露这一点。我的理解是,用于v8的JIT编译器以及其他人可能不会花费那个优化时间,因为通常eval()是用于代码的微不足道的。