18

What are the differences between the two solutions below ? In particular, is there a good reason to favour 2 over 1. (note: Please assume the name of the script to load is known. The question is just about if there is value in creating a minimal script to load a script in the given situation )

1 - Script At The Bottom

<html>
<body>
...
...
<script src='myScript.js'></script>
</body>
</html>

2 - Script at the bottom loads external script

<html>
<body>
...
...
<script>
    // minimal script to load another script
    var script = document.createElement('script');
    script.src = 'myScript.js'
    document.body.appendChild(script);
</script>
</body>
</html>
Salman A
  • 229,425
  • 77
  • 398
  • 489
Zo72
  • 13,193
  • 16
  • 65
  • 98
  • @Mahdi I check that question. I don't see why the two questions are related... – Zo72 Mar 31 '14 at 12:39
  • @Mahdi there's no problem with appending. Read more carefully, please. – Dropout Mar 31 '14 at 12:44
  • @Zo72 They are explaining what are the effects and difference between each ways. Isn't that what you were looking for, before the edit actually? – Mahdi Mar 31 '14 at 12:49
  • @Dropout I didn't say there is a problem with appending. If you read the other question, you will see why I was flagging that as duplicated. Also please consider that the original post is edited -- which is fine and clears the air, however I did flag it before the edit. – Mahdi Mar 31 '14 at 12:52
  • @Mahdi can you remove the link to the unrelated question please ? – Zo72 Apr 01 '14 at 09:38
  • @Zo72 Shouldn't this be the accepted answer ? http://stackoverflow.com/a/22957114/1491212 – Armel Larcier Apr 09 '14 at 20:23

5 Answers5

11

One important feature of the second one is that it allows the browser to finish parsing the page immediately, without waiting for the script to load. That's because the first example allows the script to use document.write to change the parsing state around the <script> tag, while the second one doesn't.

Now, we know that it's at the bottom of the page so that there isn't any important content left to parse, but this is still an important difference. It's not until parsing is done that the browser fires the popular DOMContentLoaded event. In method 1, the event fires after the script loads and executes. In method 2, the event fires before the script starts loading.

Here are some examples. In these demos, a DOMContentLoaded listener changes the background color to yellow. We try to load a script that takes 3 seconds to load.

  1. http://jsfiddle.net/35ccs/
  2. http://jsfiddle.net/VtwUV/

(edit: Maybe jsfiddle wasn't the best place to host these demos. It doesn't show the result until the slow-loading script loads. Be sure to click Run again once it loads, to see what happens.)

Pick the approach that's best for your application. If you know you need the script to run before DOMContentLoaded, go with method 1. Otherwise, method 2 is pretty good in most cases.

guest
  • 5,790
  • 23
  • 39
5

1. Script at the bottom

When you use a "synchronous" script tag, it will block the browser from rendering the page until the script is loaded and executed. This method has the following effects:

  • Regardless of where you put the script tag, the browser cannot fire DOMContentLoaded until the script is downloaded and executed.

  • Placing such a script tag at the bottom only ensures that the browsers has rendered all content before getting blocked by the script.

2. Script at the bottom loads external script

When you inject a script tag using JavaScript, it will create an "asynchronous" script tag that does not block the browser. This method has the following effects:

  • Regardless of where you put the JavaScript code that generates the script tag, the browser executes it as soon as it is available without blocking the page. The DOMContentLoaded fires when it should; irrespective of whether the script has downloaded/executed.

The second approach has the following advantages:

  • The script that injects a script tag can be placed anywhere including document head.
  • The script will not block the rendering.
  • DOMContentLoaded event does not wait for the script.

The second approach has the following disadvantages:

  • You cannot use document.write in such scripts. If you do, such statements might wipe the document clean.
  • Asynchronous execution does not mean that browser has finished parsing the page. Keep the script executes as soon as it is available clause in mind.
  • Execution order is not guaranteed. Example: If you load "library.js" and "use-library.js" using injected script tags, it is possible for "use-library.js" to load and execute before "library.js".

Having said all that, there is another method for loading scripts, with three variations:

<script src="myScript.js" async></script>
<script src="myScript.js" defer></script>
<script src="myScript.js" async defer></script>

Regarding Steve Souders's work: he proposed 6 techniques for loading scripts without blocking. The async and defer attributes introduced in HTML5 cover the Script DOM Element and Script Defer techniques and their browser support is more than enough for you to worry about the other techniques.

Salman A
  • 229,425
  • 77
  • 398
  • 489
3

These two ways of initializing a script are basically the same, although theres no reason to use the second way if you can directly put in the result. However you can wrap the second example in a $(document).ready() method for example which would lead to sort of a lazy loading effect. This basically means that the page would load first and after the loading of the page is finished it would load the script. Or of course you can create a method which initializes a certain script this way. It's useful when you have a large script which is used only in some situations. This would prevent loading it unless you need it, thus decreasing the overall loading time.

Dropout
  • 12,137
  • 9
  • 47
  • 96
  • you are probably right when you say: "although theres no reason to use the second way if you can directly put in the result"... but do you know for sure ? – Zo72 Mar 31 '14 at 12:41
  • @Zo72 I am probably sure ;) Check the results in your browser's console (networking and source tabs, don't use CTRL+U). – Dropout Mar 31 '14 at 12:42
  • @Dropout I'd +1 but there is no enough content – rowly Mar 31 '14 at 17:58
  • @rowly is an example of such initialization method enough content? I would be glad to provide more info, but it's kind of a broad topic. – Dropout Apr 01 '14 at 06:16
  • there is no jQuery on the example – Josmar Apr 08 '14 at 04:09
2

This isn't a direct answer to your question, but it's good to know regardless.

The 2nd approach is sometimes used as a library fallback.
For example, you load jQuery from the Google CDN. But, if it were to fail for any reason, load jQuery from your own local copy.

Here's how the popular HTML5 Boilerplate recommends doing this:

    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
    <script>window.jQuery || document.write('<script src="js/vendor/jquery-1.11.0.min.js"><\/script>')</script>
Scott Rippey
  • 14,881
  • 5
  • 68
  • 83
1

The first method means that the script tag is hardcoded in. The second method dynamically adds a script tag to the bottom of the page using JavaScript. The benefit of the second method is that you can add additional logic if needed to modify the script tag. Perhaps you might want to load a different script file based on culture, browser or some other factor you can determine in JavaScript. The second method also causes the JavaScript file to be loaded without blocking the loading of the rest of the web page. In method one the page will stop loading when it gets to the script tag, load the JavaScript file, then finish loading the rest of the page. Since this tag is at the bottom of your page it doesn't make too much of a difference.

If you are creating a Windows Store app using JavaScript then the first method is recommended as this will allow the app to bytecode cache the JavaScript file which will make it load up faster.

rbrundritt
  • 14,135
  • 2
  • 19
  • 41