Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

document.createElement("script") synchronously

Is it possible to call in a .js file synchronously and then use it immediately afterward?

<script type="text/javascript">     var head = document.getElementsByTagName('head').item(0);     var script = document.createElement('script');     script.setAttribute('type', 'text/javascript');     script.setAttribute('src', 'http://mysite/my.js');     head.appendChild(script);      myFunction(); // Fails because it hasn't loaded from my.js yet.      window.onload = function() {         // Works most of the time but not all of the time.         // Especially if my.js injects another script that contains myFunction().         myFunction();     }; </script> 

This is simplified. In my implementation the createElement stuff is in a function. I thought about adding something to the function that could check to see if a certain variable was instantiated before returning control. But then there is still the problem of what to do when including js from another site that I have no control over.

Thoughts?

Edit:

I've accepted the best answer for now because it gives a good explanation for what's going on. But if anyone has any suggestions for how to improve this I'm open to them. Here's an example of what I'd like to do.

// Include() is a custom function to import js. Include('my1.js'); Include('my2.js');  myFunc1('blarg'); myFunc2('bleet'); 

I just want to keep from having to know the internals too much and just be able to say, "I wish to use this module, and now I will use some code from it."

like image 379
Josh Johnson Avatar asked Jul 14 '10 16:07

Josh Johnson


People also ask

Are script tags loaded synchronously?

Synchronous loading of the scriptjs is loaded only when the loading of FirstScript. js is complete. Similarly, all requests are handled synchronously.

Is appendChild synchronous?

appendChild(s) console. log(myVar); will output hello world to the console, thus proving that appendChild is entirely synchronous.


2 Answers

You can create your <script> element with an "onload" handler, and that will be called when the script has been loaded and evaluated by the browser.

var script = document.createElement('script'); script.onload = function() {   alert("Script loaded and ready"); }; script.src = "http://whatever.com/the/script.js"; document.getElementsByTagName('head')[0].appendChild(script); 

You can't do it synchronously.

edit — it's been pointed out that, true to form, IE doesn't fire a "load" event on <script> tags being loaded/evaluated. Thus I suppose the next thing to do would be to fetch the script with an XMLHttpRequest and then eval() it yourself. (Or, I suppose, stuff the text into a <script> tag you add; the execution environment of eval() is affected by the local scope, so it won't necessarily do what you want it to do.)

editAs of early 2013, I'd strongly advise looking into a more robust script loading tool like Requirejs. There are a lot of special cases to worry about. For really simple situations, there's yepnope, which is now built into Modernizr.

like image 95
Pointy Avatar answered Oct 07 '22 19:10

Pointy


This isn't pretty, but it works:

<script type="text/javascript">   document.write('<script type="text/javascript" src="other.js"></script>'); </script>  <script type="text/javascript">   functionFromOther(); </script> 

Or

<script type="text/javascript">   document.write('<script type="text/javascript" src="other.js"></script>');   window.onload = function() {     functionFromOther();   }; </script> 

The script must be included either in a separate <script> tag or before window.onload().

This will not work:

<script type="text/javascript">   document.write('<script type="text/javascript" src="other.js"></script>');   functionFromOther(); // Error </script> 

The same can be done with creating a node, as Pointy did, but only in FF. You have no guarantee when the script will be ready in other browsers.

Being an XML Purist I really hate this. But it does work predictably. You could easily wrap those ugly document.write()s so you don't have to look at them. You could even do tests and create a node and append it then fall back on document.write().

like image 41
Josh Johnson Avatar answered Oct 07 '22 20:10

Josh Johnson