0

I have been building script tag using javascript.when I use this script to load the three other scripts,the script is not loading in order.I want jquery.min.js to get loaded first. So I have used that as the first parameter. But it is not getting loaded at first. so I have been caught up with reference error. Can anyone tell me what mistake I have done in this code. My code is here

<script type="text/javascript">
(function (a, b, c) {
    var g = document.createElement('script');
    g.type = 'text/javascript';
    g.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://') + a;
    var s = document.getElementsByTagName('script')[0];
    s.parentNode.insertBefore(g, s);
    var g = document.createElement('script');
    g.type = 'text/javascript';
    g.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + b;
    var s = document.getElementsByTagName('script')[0];
    s.parentNode.insertBefore(g, s);
    var g = document.createElement('script');
    g.type = 'text/javascript';
    g.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + c;
    var s = document.getElementsByTagName('script')[0];
    s.parentNode.insertBefore(g, s);

})('ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js', '.example.com/js/script.js', '.example.com/js/form.js');
</script>
Ganesh Babu
  • 3,590
  • 11
  • 34
  • 67
  • canm u make a jsfiddle. Is the first script there? Is there a script tag already present before running this? Why aren't u appending this to body? – SoWhat Aug 21 '13 at 06:17
  • Also where are u getting the reference error? – SoWhat Aug 21 '13 at 06:18
  • Reference error is this:$ is not defined. It means that jquery.min.js is not loaded at first. – Ganesh Babu Aug 21 '13 at 06:22
  • Well, think it this way: You're inserting jQuery and then some other scripts BEFORE it. Basically, you're loading from "c" to "a", but you should load them in order ("a" to "c"). Maybe the problem is `insertBefore()`? Have you tried using `s.parentNode.insertBefore(g, s.nextSibling);`? Also, I think `var s` should not be a ` – Alejandro Iván Aug 21 '13 at 06:57

5 Answers5

2

After my studing around this toppics, I updated for who visit to this question later.

For most of the browsers (IE9, Firefox, Chrome, Safari, ...) except Opera (12.16), dynamic script injection into DOM will load script asynchronously.

So this code:

function loadScript(src) {
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = src;
}
loadScript('script1.js');
loadScript('script2.js');
loadScript('script3.js');

is almost equivalent to:

<script src="script1.js" async></script>
<script src="script2.js" async></script>
<script src="script3.js" async></script>

But if the async flag is set to false explicitly like:

function loadScript(src) {
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = src;
    script.async = false;
}

then the scripts will be loaded in order synchronously.

So the very short answer for this question is that g.async = false, but still I also recommend to use some framework and that is the best answer.

Try this: http://jsfiddle.net/DRCzN/

~~~~ original answer ~~~~~~

Dynamic script insertion (createElement('script') then insertBefore() or even insertAfter()) will load each script asynchronously.

So with your current script, the arrival of those script to the browser heavily depends on the network status.

If you want keep the dependency of these scripts, you can use some script loader such as $script, head.js or Require.js.

EDIT: I like Jonathan's solution, and here is a little improvement using $.getScript().

if script.js and form.js are independent of each other

<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript">
(function(scripts) {
    var protocol = ('https:' == document.location.protocol ? 'https://ssl.' : 'http://www.');
    $.each(scripts, function(i, s) {
        $.getScript(protocol + s);
    });
})(['.example.com/js/script.js', '.example.com/js/form.js']);
</script>

if form.js depneds on script.js

<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript">
(function(scripts) {
    var protocol = ('https:' == document.location.protocol ? 'https://ssl.' : 'http://www.');
    $.getScript(protocol + scripts[0], function() {
        $.getScript(protocol + scripts[1]);
    });
})(['.example.com/js/script.js', '.example.com/js/form.js']);
</script>
tokkonopapa
  • 167
  • 4
  • I agree with your answer. Does that mean "g.async=true" can solve this issue? But when tried, it didn't worked? – Ganesh Babu Aug 21 '13 at 06:52
  • No. `g.async=true` doesn't solve your problem. Almost all browsers don't need async flag to load script asynchronously with dynamic insertion except old firefox. By the way, how about using `document.write()` ? – tokkonopapa Aug 21 '13 at 07:02
  • You are correct. Require.js solved the issue. But it's working crazy. When I load the page, it isn't working.when I type the url and press enter it's working. Does that deals with asynchronous script loading? If so how can then we solve this?? – Ganesh Babu Aug 21 '13 at 07:15
  • Ok, I agree that head.js is a little bit difficult to use. I think the @Jonathan 's answer is good for you if you wrap `(function (scripts) {...})(...)` with `$(function() {...});` (document ready). – tokkonopapa Aug 21 '13 at 07:37
  • We are loading jquery.js using javascript. Then how can we use $(function() {...});(document ready) ?? It didn't work – Ganesh Babu Aug 21 '13 at 07:45
  • 1
    I was wrong because you don't need to wait document ready. I think Jonathan's code will work but it assumes there is no dependency between script.js and form.js. His code will still load those scripts asynchronously. Please check this [fiddle](http://jsfiddle.net/tokkonoPapa/9hZKX/) and try to change the delay. – tokkonopapa Aug 21 '13 at 09:39
2

Use require.js for dynamic script loading.It will work.Also, try to use jquery.js above the website rather generate using script.

Ganesh Babu
  • 3,590
  • 11
  • 34
  • 67
0

It's close, but use insertAfter, and remember to increase the index for each script.

var s = document.getElementsByTagName('script')[0];
g.parentNode.insertBefore(s, g.nextSibling);

...
var s = document.getElementsByTagName('script')[1];
g.parentNode.insertBefore(s, g.nextSibling);

...
var s = document.getElementsByTagName('script')[2];
g.parentNode.insertBefore(s, g.nextSibling);
Ringo
  • 5,097
  • 3
  • 31
  • 46
  • Its showing error again i.e.,Uncaught TypeError: Object # has no method 'insertAfter' – Ganesh Babu Aug 21 '13 at 06:25
  • Oops. Well you need to insert after... that's the problem you're having. So check this out: http://stackoverflow.com/questions/4793604/how-to-do-insert-after-in-javascript-without-using-a-library – Ringo Aug 21 '13 at 06:27
  • ok, i edited my answer. hopefully this will work for ya. although it still says insertBefore(), it will hopefully insert after, as that solution says it will. – Ringo Aug 21 '13 at 06:35
  • Thanks.. But still it shows some other error: Cannot call method 'insertBefore' of null – Ganesh Babu Aug 21 '13 at 06:51
0

Here's another example. This one uses an array of scripts to add, reverses them and then inserts after the current script tag.

EDIT: Can you get away with loading jQuery directly, as below. Using // a the start will make the resource load under the current protocol.

<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript">
(function (scripts) {

    var protocol = ('https:' == document.location.protocol ? 'https://ssl.' : 'http://www.'),
        thisScript = document.getElementsByTagName('script')[0];

    function createScriptTag(element, index, array) {
        var newScript = document.createElement('script');
        newScript.type = 'text/javascript';
        newScript.src = protocol + element;
        thisScript.parentNode.insertBefore(newScript, thisScript.nextSibling);
    };

    (scripts || []).reverse().forEach(createScriptTag);

})(['example.com/js/script.js', 'example.com/js/form.js']);
</script>
Jonathan
  • 5,953
  • 1
  • 26
  • 35
  • Thanks for the improved solution .But I still cannot clear that issue. Your code also doesn't load jquery.min.js at first!!! – Ganesh Babu Aug 21 '13 at 06:40
  • @tyganeshbabu if all you're trying to do is load http/https could you not use `//` at the start of the `src` value? – Jonathan Aug 21 '13 at 07:06
0

Here is another method of solving this problem :

<script type="text/javascript">
window.onload = function () {
    "use strict";
    function js(n) {
        var s = document.createElement('script');
        s.setAttribute("type", "text/javascript");
        s.setAttribute("src", n);
        document.getElementsByTagName("head")[0].appendChild(s);
    }
    js("http://requirejs.org/docs/release/2.1.8/minified/require.js");
    js("http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js");
    js("http://www.example.com/form.js");
    js("http://www.example.com/script.js");
};
</script>

This can also be used rather than the code explained in question.

Ganesh Babu
  • 3,590
  • 11
  • 34
  • 67