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:
first.js
. Anything that require changes to the original HTML of the page, or to second.js
, is not acceptable.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
.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...
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
In first.js
, set var shouldILoad = true
Then, load second.js
this way:
<script> if (shouldILoad) { (function() { var myscript = document.createElement('script'); myscript.type = 'text/javascript'; myscript.src = ('second.js'); var s = document.getElementById('myscript'); s.parentNode.insertBefore(myscript, s); })(); } </script>
(where 'myscript' is the ID of some element before which you'd like to insert the new Script element)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With