我已经看到很多关于如何动态添加代码的建议,如(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的副本,它处理功能差异,这里我想要性能和安全性差异。
答案 0 :(得分:7)
不,使用<script>
代码与使用eval
相比,没有任何性能提升。在您提供的两个示例中,eval
在我测试的所有浏览器中都要快得多。部分不同之处在于使用<script>
,除了运行脚本之外,它还在修改DOM,但并不是全部。使用较长的脚本时,差异并不明显,但eval
仍然更快:
更新:我更新了演示,以便更好地匹配测试(两者现在都在创建script
块)。结果仍然显示eval
要快得多。
jsPerf:http://jsperf.com/stackoverflow-8380204-eval-vs-script
因此,不使用eval
的原因仅与安全相关。来自Why is using the JavaScript eval function a bad idea?上接受的答案:
- 不当使用eval会打开您的注射攻击代码
- 调试可能更具挑战性(没有行号等)
醇>
还有第三个谈论速度,但在答案的评论中反驳了。如果您无法保证计划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()是用于代码的微不足道的。