|
|||||||
New to SitePoint Forums? Register here for free!
|
![]() |
|
|
Thread Tools | Display Modes |
|
|
#1 |
|
Community Advisor
![]() ![]() Join Date: Mar 2009
Location: Melbourne, Australia
Posts: 3,357
|
Scripts in Head or at end of Document? Pros / Cons
I'm new to JavaScript, and my initial understanding is that it's better to link to external scripts in the head of the document rather than at the end of the document. There are hassles with <head> links, though, such as having to prevent the script running until the page is loaded.
Often I see scripts linked near the end of the <body> section, which seems to have some advantages. Would anyone be interested in listing / discussing the pros and cons of both approaches? Is linking to scripts at the bottom of the <body> a bad thing? I'm interested in this not only from a convenience point of view but also from a best-practice angle. Interested in any replies or links to other discussions. ![]() |
|
|
|
|
|
#2 |
|
Follow Me On Twitter: @djg
![]() ![]() ![]() ![]() ![]() Join Date: Aug 2000
Location: Philadephia, PA
Posts: 20,206
|
I put locally hosted scripts in the head of the document, compressed when they're any significant size. Minimize the number of files when possible to reduce the number of requests the browser has to make to the server. My reasons for that are:
1) It just seems more tidy to have all the scripts in one place 2) I usually use a CMS or framework that handles putting the necessary scripts for a page in the head, pasting them into the body of individual pages makes it harder to keep track of them Externally hosted scripts usually go at the end of the document so that they don't prevent your page from loading if the external server is slow. This is common for things like web stats / counters and conversion tracking code. |
|
|
|
|
|
#3 |
|
Community Advisor
![]() ![]() Join Date: Mar 2009
Location: Melbourne, Australia
Posts: 3,357
|
Thanks for the reply, Dan.
In the CMSs I've used, it wouldn't be a problem to have the script links in an include which could be placed at the bottom of a template. But I guess it's a bit messier. I don't understand window.onload fully, but it seems a little strange to me that workarounds are needed if you want to have more than one function triggered on page load. That's partly why I've started to question links going in the head section. It seems window.onload can be dispensed with if the scripts are loaded last. Or is that a misconception? I'm starting to wonder if a decision should be made on a script by script basis. Some scripts need to be loaded before the page loads (like jQuery?), while others are better loaded after the page content. Looking forward to more opinions on this. |
|
|
|
|
|
#4 | |
|
SitePoint Author
![]() ![]() ![]() Join Date: Nov 2004
Location: Ankh-Morpork
Posts: 12,259
|
Quote:
The only reason to put scripts in the head these days is probably if you have a server-side app that generates bits of each page in different places (e.g., Java frameworks like JSF or Seam) and your templates are not constructed properly.
__________________
Birnam wood is come to Dunsinane |
|
|
|
|
|
|
#5 | ||
|
Community Advisor
![]() ![]() Join Date: Mar 2009
Location: Melbourne, Australia
Posts: 3,357
|
Heh heh, good question. I double-checked the books I have before starting this thread (such as Simply JavaScript), and they all direct you to place external links in the <head> section. I couldn't find a mention of placing them anywhere else, as if the idea is unthinkable. Yet I'm seeing the pre </body> more and more, and hence the question.
Quote:
Quote:
![]() |
||
|
|
|
|
|
#6 |
|
SitePoint Wizard
![]() Join Date: Jul 2008
Posts: 5,758
|
There's some scenarios well served by putting (some) javascript in the head, but generally, I put it all at the end of the doc.
|
|
|
|
|
|
#7 |
|
Community Advisor
![]() ![]() Join Date: Mar 2009
Location: Melbourne, Australia
Posts: 3,357
|
Are you able to list any of those? I'd find it interesting to have a list for future reference. I was wondering about things like jQuery, but it might depend on what it's being asked to do, I suppose.
|
|
|
|
|
|
#8 |
|
Follow Me On Twitter: @djg
![]() ![]() ![]() ![]() ![]() Join Date: Aug 2000
Location: Philadephia, PA
Posts: 20,206
|
Here's an on-topic question for the JS gurus: If a script contains code that runs when the DOM is ready (e.g. jQuery's $(document).ready), and this script is included at the end of the document, might the DOM-ready trigger fire before the script has loaded, thus never running?
|
|
|
|
|
|
#9 |
|
Program Your Site Team
![]() ![]() ![]() Join Date: Jul 2005
Location: West Springfield, Massachusetts
Posts: 11,231
|
When I first started years ago I put my javascript all over the place, including lots of inline script. ... Progress due to maintenance nightmares. I started to reference external javacript files from script tags in the head. This was so functions would be available for the remaining inline function calls when the DOM loaded in. I have since removed inline function calls from my mark-up. But for the longest time it just didn't "feel right" referencing js files anywhere other than the head. I guess part of me felt it was taking a step backwards or something.
Just as where my earlier inline function calls needed the script to already have been loaded, I eventually noticed that some scripts needed the DOM to be loaded (eg. getElementById('wrapper')) and I needed to use onload(). Right now I do something like function doStuffA(){} function doStuffB(){} function doStuffC(){} function init(){ doStuffA(); doStuffB(); doStuffC(); } referenced in the head. And I have onload = init; and Google analytics before the closing body tag. I forget now and I imagine things have changed some, but I remember reading about there being browser differences in what sequence things loaded in. But I guess the main thing is to determine what needs what to be already loaded in when it's needed.
__________________
10 Rules for Driving Traffic Using Forums Ultimate SEO Checklist How to be a Great Online Community Member Fluff posting - what is it and how do we deal with it? SitePoint's September Contest!! Do You Want to Be Our Judge? |
|
|
|
|
|
#10 | |
|
SitePoint Wizard
![]() Join Date: Jul 2008
Posts: 5,758
|
Quote:
You can usually get a good compromise by just getting the right styles loading early so the ui will be progressively rendering as the suitable js or non-js ui. But, sometimes things are more complicated and css and noscript solutions are messy. You might even find it nice to have a small javascript widget up and running asap as the page loads. For example, I personally like it when the js nav menu is usable right away before the rest of the page loads. |
|
|
|
|
|
|
#11 | |
|
SitePoint Wizard
![]() Join Date: Jul 2008
Posts: 5,758
|
Quote:
Regardless, your function will get called. It checks if the event already fired, and either queues your function up with any others that might have been queued, or just calls it. |
|
|
|
|
|
|
#12 | |
|
SitePoint Author
![]() ![]() ![]() Join Date: Nov 2004
Location: Ankh-Morpork
Posts: 12,259
|
Quote:
But since the <script> tag is part of the DOM, my guess is that the DOM-ready even would occur after the the script has been loaded and executed. In my eyes it's a moot question, though, since there's no reason to use the event if the script is already after the content.
__________________
Birnam wood is come to Dunsinane |
|
|
|
|
|
|
#13 | |
|
Islomaniac
![]() ![]() ![]() ![]() Join Date: Sep 2005
Location: Cambridge, UK
Posts: 4,268
|
Quote:
HTML Code:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html> <head> <title>Testing ondomcontentloaded</title> <script type="text/javascript"> function addP(txt) { var li = document.createElement('li'); li.appendChild(document.createTextNode(txt)); document.getElementById('stages').appendChild(li); } document.addEventListener('DOMContentLoaded', function() { addP('DOMContentLoaded from head'); }, false); window.onload = function() { addP('window.onload'); } </script> </head> <body onload="addP('body onload attribute')"> <h1>when exactly does DOMContentLoaded fire?</h1> <ol id="stages"> </ol> <script type="text/javascript"> addP('before domcontentloaded trigger at body bottom'); </script> <script type="text/javascript"> document.addEventListener('DOMContentLoaded', function() { addP('DOMContentLoaded from body bottom'); }, false); </script> <script type="text/javascript"> addP('after domcontentloaded trigger at body bottom'); </script> </body> <script type="text/javascript"> document.addEventListener('DOMContentLoaded', function() { addP('DOMContentLoaded after closing body tag'); }, false); </script> </html> <script type="text/javascript"> document.addEventListener('DOMContentLoaded', function() { addP('DOMContentLoaded after closing html tag'); }, false); </script> Results:
It seems like DOMContentLoaded fires right after absolutely everything in the HTML source has been parsed, but before window.onload, which as Tommy said (regarding <script> being a part of the DOM) makes sense. Interestingly, having an onload="" attribute in the <body> overwrites window.onload in javascript (at least in FF3.6) - even if the attribute is empty or wrong. Hence why window.onload isn't part of the results. I wasn't expecting that to happen, but I suppose it makes sense. So anyway, DOMContentLoaded can be used anywhere, stupidly or otherwise. ![]() |
|
|
|
|
|
|
#14 |
|
SitePoint Addict
![]() Join Date: Sep 2008
Location: Manchester, UK
Posts: 327
|
Hmmm very interesting question and answers! I've seen this a few times on some blogs as well about referencing external JS files at the bottom of the page (before the closing body tag) but I've always referenced external JS files in the head because that's what books encourage and it's what most people seem to do.
I guess I'd like to add a question to this thread. Which way should you reference external JavaScript files? In the head of the document or at the bottom of the document before the closing body tag? If there isn't a defined way in which you should reference external JS files (and referencing them in the head is just the most popular way) then which would you recommend? Andrew Cooper
__________________
SitePoint References: HTML, CSS, JavaScript W3C Technical Recommendations: HTML 4.01, CSS 2.1 Educational Resources: Opera WSC, WaSP InterACT Curriculum SitePoint Courses: CSS Live, JavaScript Live |
|
|
|
|
|
#15 |
|
Islomaniac
![]() ![]() ![]() ![]() Join Date: Sep 2005
Location: Cambridge, UK
Posts: 4,268
|
Andrew, how are your questions any different to Ralph's original, and how are they not answered already?
|
|
|
|
|
|
#16 | |
|
SitePoint Addict
![]() Join Date: Sep 2008
Location: Manchester, UK
Posts: 327
|
Quote:
I know most people reference external JS files in the head of the HTML document, but JS gurus reference it before the closing body tag but this may just be for performance increases, it may not be the standard way of referencing an external JS file. So yea, I'm asking for confirmation on which method should be used. And the second question is me asking what method should be used if neither of them are a set standard for referencing external JS files. Andrew Cooper
__________________
SitePoint References: HTML, CSS, JavaScript W3C Technical Recommendations: HTML 4.01, CSS 2.1 Educational Resources: Opera WSC, WaSP InterACT Curriculum SitePoint Courses: CSS Live, JavaScript Live |
|
|
|
|
|
|
#17 |
|
Programming Since 1978
![]() ![]() ![]() ![]() Join Date: Sep 2005
Location: Sydney, NSW, Australia
Posts: 13,104
|
Another consideration is that unlike other files where the browser can download between two and eight files at once, whenever the browser starts downloading a JavaScript file everything else stops until the browser finishes downloading that file.
If you care going to place JavaScript of more than a half dozen lines of code in the head of the page then you should replace that code with JavaScript that adds the script tags to the head dynamically so that the JavaScripts are downloaded dynamically by JavaScript itself and not by the browser. That way they do not hold up the downloading of the other files AND multiple JavaScripts can download at the same time because the one file at a time limit only applies to JavaScript downloaded directly by the browser. You avoid that issue if you place the scripts at the end of the body. At the end of the body you no longer need to test for if the DOM has loaded if the page is HTML because any element in the HTML DOM can be accessed immediately that element has loaded without waiting for the rest of the page. It is only with XHTML that the entire DOM is inaccessible until everything has loaded.
__________________
Stephen J Chapman HTML Help, CSS Help, JavaScript Help, PHP/mySQL Help, blog Book Reviews, About JavaScript scripts and tutorials follow me on Twitter |
|
|
|
|
|
#18 | ||
|
Follow Me On Twitter: @djg
![]() ![]() ![]() ![]() ![]() Join Date: Aug 2000
Location: Philadephia, PA
Posts: 20,206
|
Quote:
1) Maybe I'd like to take some advice here and move scripts to the end of the document without rewriting them 2) Just about every jQuery plugin on the web tells you to use document.ready, lots of people are just going to copy and paste that, I wanted to know if it'd still behave as usual as part of the <body> Quote:
![]() |
||
|
|
|
|
|
#19 | |
|
SitePoint Wizard
![]() Join Date: Jul 2008
Posts: 5,758
|
Quote:
![]() http://www.stevesouders.com/blog/201...ading-roundup/ |
|
|
|
|
|
|
#20 | |
|
SitePoint Author
![]() ![]() ![]() Join Date: Nov 2004
Location: Ankh-Morpork
Posts: 12,259
|
No, I didn't say you were stupid for asking the question. I only wondered why you'd want to do something as stupid as using an event handler for something that was already at the end of the document.
Quote:
![]()
__________________
Birnam wood is come to Dunsinane |
|
|
|
|
|
|
#21 |
|
Follow Me On Twitter: @djg
![]() ![]() ![]() ![]() ![]() Join Date: Aug 2000
Location: Philadephia, PA
Posts: 20,206
|
If it's not necessary to make any changes to get the same behavior, then it really is that much work -- when the benefit is 0, divide anything by it and you get the same infinite waste of time. It was just a question with a non-obvious (to me) answer -- whether ready() is really an event handler and whether that 'event' fires if a script loads after the entire document is downloaded and, potentially, the document object has already been fully constructed.
Since jQuery's ready() will run even if that code appears after the DOM is ready (according to Raffles' demo), it's not acting much like an event handler, and more like a procedure -- check if the DOM is ready right now (don't wait for an event to notify me of it), and if not, check again until it is. But I've never looked into how ready() is implemented to know that. |
|
|
|
|
|
#22 | |
|
Unobtrusively zen
![]() ![]() Join Date: Jan 2007
Location: Christchurch, New Zealand
Posts: 8,016
|
Quote:
These days there is a shorter DOM ready method, and that is the jQuery callback javascript Code:
|
|
|
|
|
|
|
#23 |
|
Site Point Member
![]() Join Date: Aug 2007
Location: Netherlands
Posts: 5,955
|
My (beginners) books also said to put JS in the <head>... they usually say this after pounding on the importance of separation of content and behaviour. Maybe because some of us are CSS people, we see <scripts> in the <body> similar to <style> tags in the head (instead of external). This is the reason why I haven't been putting scripts in my <body>. It feels dirty when you've had the last 3-4 years of being told only HTML in the HTML, only CSS in the CSS...
If I have multiple pages running the same script, it doesn't make sense to put it in the HTML to me then either... don't I want caching? Analytics are meant to be per-page (and I'm allergic to them anyway) so they make sense to sit in the <body> I suppose. Another reason: if for whatever reason I needed my page section 508 compliant (hopefully never), it requires a noscript tag for every script tag that sits in the body. Since many situations of good, unobtrusive JS don't need (and shouldn't have) a noscript tag, I can imagine going through flaming hoops even, just to keep the scripts referenced in the <head>. When I'm building and testing, I always have the scripts in the body, but I'll also have <style> tags too, simply because when starting something out, One Document to Rule Them All. Chris Heilmann is someone I'm more than willing to listen to, though, so he could well convince me to start throwing more stuff into the HTML... the performance issues mentioned, to me that would depend on how many pages are running it (again, isn't caching an issue? or not?) and I wonder if it doesn't just make sense to have some slower load event handler if I'm also calling some lib every time as well? ralph: did you read the article Paul listed re 7 sins of JS? In that article there are links to other articles by Heilmann too including an AJAX one that was interesting to read even if you do absolutely nothing with AJAX. *edit http://www.sitepoint.com/forums/showthread.php?t=662004 |
|
|
|
|
|
#24 | |
|
SitePoint Author
![]() ![]() ![]() Join Date: Nov 2004
Location: Ankh-Morpork
Posts: 12,259
|
Quote:
So a better comparison would be whether to use a <style> tag with an internal style sheet or to use a <link> tag referring to an external style sheet.
__________________
Birnam wood is come to Dunsinane |
|
|
|
|
|
|
#25 | |
|
Site Point Member
![]() Join Date: Aug 2007
Location: Netherlands
Posts: 5,955
|
Quote:
So I also don't necessarily mean <script type="text/javascript> a bunch of JS... </script> but if every page is calling the same script at the bottom of the body: <script src="foo.js" type="text/javascript"></script> Actually I have a page where I took a script from someone, which sits externally, but didn't have an event loader, and this was for a dropdown menu on every single page... and I ended up having <script type="text/javascript">dropdown('menu', 'hover', 300);</script> on every page... Even if there was a CMS so I wasn't manually writing that every page, I still feel like I'd rather have that tucked away somewhere else too (but this would require a loader and if I understand this thread correctly, that's a rather large penalty?). |
|
|
|
|
![]() |
| Bookmarks |
«
Previous Thread
|
Next Thread
»
| Thread Tools | |
| Display Modes | |
|
|
|
All times are GMT -7. The time now is 13:34.




















Linear Mode
