可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have seen a lot of suggestions about how one should add code dynamically like so (source):
var myScript = document.createElement("script");
myScript.setAttribute("type","text/javascript");
myScript.innerHTML += 'alert("Hello");';
document.body.appendChild(myScript);
As opposed to eval
like so
eval('alert("Hello");');
People complain about performance drops and security issues with eval
, but I can't imagine how adding <script>
tags would be any faster or any more secure.
EDIT people would like to know why I am evaling something as trivial as alert("Hello")
, here is why:
I have a database of, lets say, 1,000,000,000,000 scripts =P obviously I can't load every one, instead the user can load whichever they wish. The scripts are stored serverside in arbritrary locations. Currently I request (xmlhttprequest interpreted as javascript) a script via its script name and the server will find it (somehow) and return it as text, which immediately gets executed/interpreted. I want to know if it would be better to return the script as text, then create a <script>
tag out of it.
Also, this is NOT a duplicate of Javascript difference between eval() and appending script tags, that deals with the functional differences, here I want the performance and security differences.
回答1:
No, there is no performance gain using <script>
tags as opposed to using eval
. In the two samples you gave, eval
is much faster in all browsers I tested. Part of the difference is that with <script>
, in addition to running the script, it's modifying the DOM, but that's not all of it. With longer scripts, the difference is not as pronounced, but eval
is still faster:
UPDATE: I updated the demo to better match the tests head-to-head (both are now creating script
blocks). The results still show eval
much faster.
jsPerf: http://jsperf.com/stackoverflow-8380204-eval-vs-script
Thus, the reasons not to use eval
are security-related only. From the accepted answer on Why is using the JavaScript eval function a bad idea?:
- Improper use of eval opens up your code for injection attacks
- Debugging can be more challenging (no line numbers, etc.)
There is a third one that talks about speed, but it is refuted in the comments of that answer. If you can't guarantee the source of the scripts you plan to eval
, it should be avoided.
As an aside: Based on your usage pattern at the end of your question, you might want to check out require.js for dynamically loading scripts.
回答2:
This is probably one of those debates that changes based upon the browser, and the programmer's own opinion. I wouldn't imagine any significant performance difference between the two approaches unless you're doing this kind of thing many many times (and even then, that'd probably be indicative if a design problem).
Just a side note; code passed to eval()
can be particularly difficult to debug, and can't be cached in the same way that asynchronous loading of JavaScript can:
(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.
})();
Note that this is different to your code, in that, this loads a script from the server, instead of writing the Javascript directly into the element. Honestly, I can't imagine why you'd want to do that when you can just load a file remotely instead.
回答3:
You do realise your doing two different things.
"eval" -> launch JS interpreter, interpret and run js code.
"script" -> get DOM to construct and inject a script node then launch JS interpreter, interpret and run js code.
Basically the browser does the same as eval just. You simply have the overhead of creating and injecting a node into the DOM
回答4:
I think eval is better becouse if you create a new element and write it to the end of body, the browser never will release this memory while the script tag exists, and this will affect the general performance in some way.
In the case of eval, the speed to parse and execute (maybe) is equal to a parsed new script tag, and the string passed maybe will be released from memory when finished.
As for security, I think it might include malicious code in your eval, you can make the inclusion in script tag as well.
Anyway, avoid both, as @jergason says, are both just as bad.
回答5:
I stumbled on this conversation while trying to solve a similar problem.
A lot of the comments are questioning what the OPs motivations are, which is valid.
My use case addresses this need... I want to load JS code from a server, but it's not an http server. The client (browser) connects via websocket and synchronizes to something like a server side DOM.
But nodes of the server DOM may want to issue JavaScript code to the user for manipulating those nodes. That code wants to come over a websocket, but then the question is how to inject it into the browser.
These pieces of code also may have dependencies, so I'm writing a websocket plugin for require.js to satisfy them.... Some parts may be static files served over httpd, but others may be dynamically generated based on user ACLs.
So... Best way to inject into browser is still unclear from this thread. Some argue that eval() is ok, but adding a script tag with innerText is another way. Another idea is to b64 encode the src value of a script tag.
There was mention somewhere on the web that dynamically injected code does not benefit from certain code optimizations in v8, and suffers a significant loss of performance. A basic "alert('hello world');" would probably not reveal that. My understanding is that the JIT compiler for v8 and presumably others don't spend that optimization time because usually eval() is for trivial bits of code.