Recently I saw some HTML with only a single <script>
element in its <head>
...
<head>
<title>Example</title>
<script src="script.js" type="text/javascript"></script>
<link href="plain.css" type="text/css" rel="stylesheet" />
</head>
This script.js
then adds any other necessary <script>
elements and <link>
elements to the document using document.write(...)
: (or it could use document.createElement(...)
etc)
document.write("<link href=\"javascript-enabled.css\" type=\"text/css\" rel=\"styleshet\" />");
document.write("<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js\" type=\"text/javascript\"></script>");
document.write("<script src=\"https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.10/jquery-ui.min.js\" type=\"text/javascript\"></script>");
document.write("<link href=\"http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.0/themes/trontastic/jquery-ui.css\" type=\"text/css\" rel=\"stylesheet\" />")
document.write("<script src=\"validation.js\" type=\"text/css\"></script>")
Note that there is a plain.css
CSS file in the document <head>
and script.js
just adds any and all CSS and JavaScript which would be used by a JS-enabled user agent.
What are some of the pros and cons of this technique?
Advantages of JavaScript Speed. Client-side JavaScript is very fast because it can be run immediately within the client-side browser. Unless outside resources are required, JavaScript is unhindered by network calls to a backend server. Simplicity. JavaScript is relatively simple to learn and implement.
JavaScript is a dynamic computer programming language. It is lightweight and most commonly used as a part of the web pages, whose implementation allows a client-side script to interact with a user and to make dynamic pages. It is an interpreted programming language with object-oriented capabilities.
External JavaScript Advantages Placing scripts in external files has some advantages: It separates HTML and code. It makes HTML and JavaScript easier to read and maintain. Cached JavaScript files can speed up page loads.
document.write
will pause everything that the browser is working on the page (including parsing). It is highly recommended to avoid because of this blocking behavior. The browser has no way of knowing what you're going to shuff into the HTML text stream at that point, or whether the write will totally trash everything on the DOM tree, so it has to stop until you're finished.
Essentially, loading scrips this way will force the browser to stop parsing HTML. If your script is in-line, then the browser will also execute those scripts before it goes on. Therefore, as a side-note, it is always recommended that you defer loading scripts until after your page is parsed and you've shown a reasonable UI to the user.
If your scripts are loaded from separate files in the "src" attribute, then the scripts may not be consistently executed across all browsers.
This way, you lose a lot of the performance optimizations made by modern browsers. Also, when your scripts execute may be unpredictable.
For example, some browsers will execute the scripts right after you "write" them. In such cases, you lose parallel downloads of scripts (because the browser doesn't see the second script tag until it has downloaded and executed the first). You lose parallel downloads of scripts and stylesheets and other resources (many browsers can download resources, stylesheets and scripts all at the same time).
Some browsers defer the scripts until after the end to execute them.
The browser cannot continue to parse the HTML while document.write is going on and, in certain cases, when the scripts written are being executed due to the blocking behavior of document.write
, so your page shows up much slower.
In other words, your site has just become as slow as it was loading on a decades-old browser with no optimizations.
The reason you may want to use something like this is usually for maintainability. For instance, you may have a huge site with thousands of pages, each loading the same set of scripts and stylesheets. However, when you add a script file, you don't want to edit thousands of HTML files to add the script tags. This is particularly troublesome when loading JavaScript libraries (e.g. Dojo or jQuery) -- you have to change each HTML page when you upgrade to the next version.
The problem is that JavaScript doesn't have an @include or @import statement for you to include other files.
The solution to this is probably not by injecting scripts via document.write
, but by:
document.write
, but load the JavaScript files via XHR, then eval() them -- this may have security concerns thoughOne major disadvantage is browser incompatibility. Not all browsers correctly fetch and incorporate the resources into the DOM, so it's risky to use this approach. This is more true of stylesheets than scripts.
Another issue is one of maintainability. Concatenating and writing strings to add DOM elements on the client'side can become a maintenance nightmare. It's better to use DOM methods such as createElement to semantically create elements.
One obvious advantage is that it makes conditional use of resources much easier. You can have logic that determines which resources to load, thereby reducing the bandwidth consumption and overall processing time for the page. I would use a library call such as jQuery $.getScript() to load scripts versus document.write. The advantage being that such an approach is cleaner and also allows you to have code executed when the request is completed or fails.
Well, I may as well throw my hat in the ring on this one...
If you examine google's closure library, base.js, you will see that document.write is used in their writeScriptTag_()
function. This is an essential part of the dependency management system which 'closure' provides, and is an enormous advantage when creating a complicated, multi-file, library-base javascript application - it lets the file/code prerequisites determine loading order. We currently use this technique and have been having little trouble with it. TBH, we have not had a single issue with browser compatibility, and we test regularly on IE 6/7/8, FF3/2, Safari 4/5 and Chrome latest.
The only disadvantage that we have had so far is that it can be challenging to track down issues caused by loading a resource twice, or failing to load one at all. Since the act of loading resources is programmatic, it is subject to programmatic errors, and unlike adding the tags directly to the HTML, it can be hard to see what the exact loading order is. However, this issue can be largely overcome by using a library with some form of dependency management system such as closure, or dojo.
EDIT: I have made a few comments to this nature, but I thought it best to summarize in my answer: There are some problems with dojo.require() and jQuery.getScript() (both which ultimiately perform an ajax request and eval).
It has the advantage that you don't need to repeat the script references in each HTML file. The disadvantage is that the browser must fetch and execute the main javascript file before it may load the others.
I guess one advantage I could think of would be if you use these scripts on multiple pages, you only have to remember to include one script, and it saves some space.
At Google PageSpeed, they highly discourage you from using this technique, because it makes things slower. Apart from the sequential loading of your script.js before all the others, there's another catch:
Modern browsers use speculative parsers to more efficiently discover external resources [...] Thus, using JavaScript's document.write() to fetch external resources makes it impossible for the speculative parser to discover those resources, which can delay the download, parsing, and rendering of those resources.
It's also possible that this was written as a recommendation by an SEO firm to make the head element shorter if possible, so unique content is closer to the top of the document - also creating a higher text-to-HTML ratio. Though it does sound, all-in-all, like not a very good way of doing this; though it would make maintenance more time-consuming, a better approach would probably be to condense javascript into a single .js file and css into a single .css file, if it were deemed utterly necessary to reduce head element size.
A great disadvantage is that adding script
s into head will pause the processing of the document until those scripts were completely downloaded parsed and executed (because the browser thinks they may use document.write
). - This will hurt responsiveness.
Now days it is recommended that you put your script tags right befo </body>
. Of course this is not possible 100% of times, but if you are using unobtrusve Javascript (as you should), all scripts can be respositioned at the end of the document.
HTML5 came up with the async
attribute which suggests the browser only to execute the scripts after the main document has been loaded. This is the behaviour of script-inserted scripts in many browsers, but notin all of them.
I advise against using document.write
at all costs. Even without it, this results in one extra request towards the server. (We like to inimze the number of requests, for example with css sprites.)
And yes, as others mentioned earlier, if scriping is disabled your page will be shown without CSS (which makes it potentially unusable).
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