Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
153 views
in Technique[技术] by (71.8m points)

html - Use JavaScript to prevent a later `<script>` tag from being evaluated?

This is a bit of an oddball use case, but I have my reasons:

I'd like to be able to write

<script type="text/javascript" src="first.js"></script>
<script type="text/javascript" src="second.js"></script>

in my markup and, using the code in first.js, prevent or delay the execution of second.js. Is this possible, in any browser? What if the contents of first.js are inlined? (If it helps, assume that the second script tag has an id attribute.)

Since I've gotten a couple of answers that missed what I'm getting at, I should clarify:

  1. The solution must be entirely within first.js. Anything that require changes to the original HTML of the page, or to second.js, is not acceptable.
  2. It is acceptable to load second.js via Ajax and execute it using eval. That's the easy part. The hard part is preventing the immediate execution of second.js.
  3. Assume that you don't know what's in second.js. So, you can't just replace each global function called by second.js with a no-op function. (Plus, this would almost certainly lead to errors.)

If you know of a solution that works in some browsers but not in others, I'd love to hear it.

Example: To make this a little more concrete, let's say that the code

<script type="text/javascript">
  function func() {
    window.meaningOfLife = 42;
    window.loadSecond();
  };
  setTimeout(func, 10);
</script>

precedes the two script includes, and that second.js contains the line

if (window.meaningOfLife !== 42) {throw new Error();}

first.js should be able to prevent this error by delaying second.js from executing until window.loadSecond is run. (Assume the implementation of window.loadSecond is also in first.js.) It is not allowed to touch window.meaningOfLife.

Update: Alohci's answer meets these requirements, but only on the condition that the second script tag comes immediately after the first, with nothing but whitespace in between. If someone could extend his hack to avoid that requirement, without introducing other unwanted consequences, that would be amazing...

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Given your specific requirements set, this is actually quite simple and should work completely cross-browser. It does require however, that first.js immediately precedes second.js without anything between them except white space.

First, let's assume that the HTML looks like this:

<!DOCTYPE html>
<html>
  <head>
    <title>Test Case</title>
    <meta charset="UTF-8" />
    <script type="text/javascript">
      function func() {
        window.meaningOfLife = 42;
        window.loadSecond();
      };
    </script>
    <script type="text/javascript" src="first.js"></script>
    <script type="text/javascript" src="second.js"></script>
  </head>
  <body>
    <p>Lorem ipsum dolor sit amet ...</p>
    <a href="javascript:func()">Run Func()</a>
  </body>
</html>

I've removed the setTimeout because that can cause func() to run before start.js runs causing a "loadSecond is not defined" error. Instead, I've provided an anchor to be clicked on to run func().

Second, let's assume that second.js looks like this:

document.body.appendChild(document.createTextNode("second.js has run. "));
if (window.meaningOfLife !== 42) {throw new Error();}

Here, I've just added a line to append some text to the document body, so that it is easier to see when second.js actually runs.

Then the solution for first.js is this:

function loadSecond()
{
    var runSecond = document.createElement("script");
    runSecond.setAttribute("src", "second.js"); 
    document.body.appendChild(runSecond);
}

document.write("<script type='application/x-suppress'>");

The loadSecond function is just there to run second.js when func() runs.

The key to the solution is the document.write line. It will inject into the HTML <script type='application/x-suppress'> between the close script tag of first.js and the open script tag of second.js.

The parser will see this and start a new script element. Because the type attribute has a value which is not one that the browser recognises as being JavaScript, it will not attempt to run its content. (So there are an infinite number of possible type attribute values you could use here, but you must include a type attribute, as in its absence, the browser will assume that the script's content is JavaScript.)

The second.js script's opening tag will then be parsed as text content of the new script element and not executed. Finally the second.js script's closing tag will be re-purposed to close the new script element instead, which means that the remainder of the HTML is parsed correctly.

You can see a working version at http://www.alohci.net/static/jsprevent/jsprevent.htm


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...