I'm trying to load a remote script with some function and the execute it inline in IE9.
However I encountered an error message that my function was undefined.
What it boils down to is that IE9 (and lower, it seems) executes the script in opposite the order I would expect. I made a simplified example, which still yields the same bug for me.
<script type="text/javascript" src="multibanner_rev04_tmp.js"></script>
<script type="text/javascript">alert('nr.2');</script>
The script has a longer path I edited out for readability, it only has an alert in it and nothing else.
the alert 'nr.2' executes before the one in multibanner_rev04_tmp.js in IE9
I've tried this on multiple computers with IE9, to make sure it wasn't the same problem as this: IE9 js load order and JQuery
Problem seems to be consistent. Also tried this on IE10, which does execute the alerts in the expected order.
I don't really get what's going on here, any ideas?
From your comment on the question:
The script is injected onto my page using yet antother script (through an ad-server), so that might be a problem worth checking out.
That's a completely different thing from what you actually have in your question. What you have in your question shows script tags in the markup; injecting a script with JavaScript is completely different.
There are two ways the ad script could be adding the script to the page:
Using document.write during the main page parsing to write out a script tag. You've said your page is XHTML strict. Using document.write to output markup to the page during the main parsing is invalid in XHTML, full stop. You cannot do it. If it works at all, the behavior is unspecified and you shouldn't rely on it.
If you want to use document.write during the main page parse, you have to stop using XHTML. At that point, the scripts will be evaluated in the order the parser sees them (regardless of how they got put in the parser's input stream, from the markup or via document.write).
By creating a script element (document.createElement('script')) and then appending that to the DOM. When you do this, the script is evaluated as soon as it's available. There is no order. It's just like using the async attribute in the markup (except that it's much more cross-browser reliable).
If that's how the script is added, you cannot rely on the order. If you control the script being added in this way, you could have that script check for whatever the other script provides and use setTimeout to defer its execution until that other thing shows up. If you don't, you'll have to delay the addition of the script element until you're ready for it.
(My first ever post to stackoverflow...)
Stating the obvious...the first script tag requires the browser to load a separate script file
whereas the second script tag has the javascript inline (in the HTML).
Assuming that you have "alert('nr.1');" at the top of your multibanner_rev04_tmp.js then it appears as though IE9 is executing the inline code first even though it
appears later in the HTML, which is incorrect behaviour according to this:
http://www.w3.org/TR/html5/scripting-1.html#script
If neither attribute [async or defer] is present, then the script is
fetched and executed immediately, before the user agent continues
parsing the page.
However, using IE10 with "IE9 standards" document mode set (I don't have IE9), I can't reproduce the behaviour you are seeing, which would sort of point towards a bug in IE9 itself or a specific version of IE9? I wonder what happens if you add a defer="defer" attribute to your second script tag ? (Just for diagnosis, because it's not strictly legal according to the standard without a "src" attribute.)
Related
I am including some related content on misc. web pages by adding a <script> tag near the end of the <body> tag, which then loads other javascript files. The flow is a little convoluted, so I’ll try to explain it before asking my question:
A browser loads a page with our <script> element near the end of the <body> element
The src attribute of the script tag points to a javascript file which (in some cases) injects a second <script> element
The src attribute of the injected <script> element points to yet another javascript file, which finally injects some content on the appropriate part of the page.
We are using this two-stage approach to be able to do some basic processing before deciding whether to include the final content, which could take some time to load.
The problem is that IE8 (and maybe older versions) loads the last javascript twice. It appears that the act of setting the src attribute will trigger a load, but so will appending the script tag to the DOM. Is there any way to avoid this?
I have created a bare-bones demo of the problem. If you have some way of tracing the HTTP requests, you will see that IE8 loads js_test2.js twice.
The root difference is that IE executes a script element the first time it is added to a parent element's childNodes, regardless of whether the parent element is actually in the document. Other browsers only execute script when it is added to a node inside the document's tree of childNodes.
jQuery's domManip function (line 524 of jQuery 1.3.2), which is called by append and other similar jQuery methods, tries to be clever and calls evalScript for any <script> elements it finds in the final parsed HTML, to execute the script (by doing AJAX requests if necessary for external scripts). (The actual script elements have been removed from the parsed childNodes to stop them getting executed on insertion into the document, presumably so that scripts are only executed once when content containing them is appended into multiple elements at once.)
However, because the previous clean function, whilst parsing the HTML, appended the script element to a wrapper div, IE will have already executed the script. So you get two executions.
The best thing to do is avoid using domManip functions like append with HTML strings when you're doing anything with scripts.
In fact, forget putting your content in a serialised HTML string and getting jQuery to parse it; just do it the much more reliable plain DOM way:
var s= document.createElement('script');
s.type= 'text/javascript';
s.charset= 'UTF-8';
s.src= 'js_test2.js';
document.getElementById('some_container').appendChild(s);
(To be honest, after viewing the stomach-churning source code of the clean function, I'm having serious doubts about using jQuery's HTML-string-based DOM manipulations for anything at all. It's supposed to fix up browser bugs, but the dumb-regex processing seems to me likely to cause as many problems as it solves.)
Incidentally with this initial call:
document.write(unescape("%3Cscript src='js_test1.js' type='text/javascript'%3E%3C/script%3E"));
You don't need to unescape here; I don't know why so many people do. The sequence </ needs to be avoided in an inline script as it would end the <script> tag, and if you're doing XHTML < and & should be avoided too (or ]]> if you're using a CDATA wrapper), but there's an easier way of doing all that with just JavaScript string literals:
document.write('\x3Cscript src="js_test1.js" type="text/javascript">\x3C/script>"));
I've seen that behavior happening on other versions of IE under similar circumstances (such as cloning of <script> nodes) and I never got to know how to stop the script from executing twice, so what I ended up doing was adding a guard on the script code for it not to run twice. It was something like:
if (typeof(loaded) == 'undefined') {
// the whole code goes in here
var loaded = true;
}
If you can't find a way of preventing the script to execute twice, you may want to try that approach instead.
It would seem that jquery is fetching the second instance of js_test2 using XmlHttpRequest.
Why I don't know but its the behaviour of JQuery you need to investigate.
You can check to see if a script is already in the document before loading it-
function fetchscript(url, callback){
var S= document.getElementsByTagName('script'), L= S.length;
while(L){
if(S[--L].src== url) return true;
}
//create and append script and any callbacks
}
I find the same problem,only happen in IE.
jQuery‘s html() method chains is: html>append>domManip>clean
clean() method use innerHTML make string to DOM, innerHTML in IE has a bug that script tag will immediately load(first load), jQuery evalScript script tags at the end of domManip method(ajax load).then script file load twice in IE.
I think jQuery should fix this problem,update the clean() method
It's possible that this is because you use document.write when you're already in a <script> element. Have you tried appending to <head> instead of document.write?
I see that Javascript code is normally in heading part of HTML code.
<head>
<script type="text/javascript" language="javascript" src="core.js"></script>
...
</head>
Is it OK to put the Javascript code in a body part of HTML code? I tested it, but it seems to work.
<body>
<script type="text/javascript" language="javascript" src="core.js"></script>
...
</body>
If so, why the examples of Javascript books put the javascript code in heading part?
If not, what's the difference between putting the javascript code in body/heading part?
Not only is it OK, it's actually better, since it lets the content come first.
If your viewers have a slow (eg, mobile) connection, it's better to send the actual content first, so that they can read it while the browser downloads the Javascript.
All the people saying it is better only applies if you are talking about at the bottom of the page (and that is an up for debate thing) from a code quality point of view, it is NOT ok to sprinkle script tags through your html. All references to javascript should be in a single place on the page, either the head (where they should be), or the very bottom (as a perf optimization)
Edit:
Basically, a web page is made up of 3 pieces; style (css), structure (html), and behavior (javascript). These pieces are all very distinct, so it makes sense to keep them as separate as possible. That way if you need to change some javascript, it is all in one place. If it is sprinkled through the file, it becomes much more difficult to find the code you are looking for, and that code basically becomes noise when you are just looking at structure.
It is the same arguments as why not sprinkle db access code all over your page. It has nothing to do with technical reasons, purely an architectural/design decision. Code that does different things should be kept separate for readability, maintainability, and by extension, refactorability (not sure if that last one is actually a word...)
You can do it, and people often do.
For example, people like to put their script tags just before the closing </body> to make web pages render quicker.
Also, if you do a script block after an element is created, you don't need to wait for DOM ready.
Be warned though, don't add, or remove an element from an unclosed ancestor in the markup tree (not including the script block's immediate parent element), or you will get the dreaded Operation Aborted error in IE.
Just something to add on:
I have preference of putting Javascript file right before </body>. My reasons being that:
Content can load and be shown first. If you load huge Javascript files first, which most are meaningless until the page is loaded, the user won't be able to see anything until the JS files are loaded.
Most Javascript code require to work with the UI can only run after the UI has been loaded. Placing the codes at the end of the html file reduces the need to use the onload event handler.
It is very bad habit to place Javascript snippets all over the HTML file. Placing all at the back of the HTML file allows you to manage your Javascript more efficiently.
It is legal according to the spec.
Most examples use them in the header as the headers come first and the browser will be able to parse the reference and download the JS files faster.
Additionally, these are links and are not part of the display, so traditionally, put in the header.
It is perfectly legal but there seem to be some differing opinions about it. Those who say to put all the javascript references in the head argue that the script is downloaded before the rest of the page become visible and dependent on it. So your user will not see an object on screen, attempt to interact with it and get an error because the javascript code is not yet loaded.
On the other hand, the argument goes that it takes longer to load all the script before the user sees the page and that can have a negative impact on perceived speed of your site.
JavaScripts inside body will be executed immediately while the page loads into the browser
Placing javascript at the end of the body will defer javascript load (ie: the page will render faster), but remember that any javascript function used for an event should be loaded before the event declaration, it is mainly because users may be able to fire an event before the page is completely loaded (so before the function is loaded)!
I used to put it in the head, then I've heard that it takes longer for the page to load so I started placing the scripts at the very bottom. However, I found out the most 'clean' way to do it is to place it in the head BUT you place the script inside a document.ready function. This way you have the best of both worlds. It is cleaner because it is in the head and it is not loaded before the content has been loaded, so there aren't any problems performance wise either.
With jQuery for instance, you can do it like this:
$(document).ready(function() {
alert('test');
});
The alert will only popup when the page has been fully loaded, even though the script is in the head.
When I write the following code directly into my html page under a script tag, the string "test" gets appended to my page without replacing the rest of its content (1):
document.write("test");
However, if I place that same code into a separate javascript file like (2):
<script src="http://127.0.0.1/whatever.js" type="text/javascript"></script>
Suddenly that same code rewrites my entire page.
Is there a way to perform a document.write() from a remote file and get the result in (1)?
Thanks for your time.
If you use doc.write while the page page is rendering, it will insert or append the string. If you use doc.write after it's rendered, or after window.onload, it will essentially begin the rendering process again, and overwrite the page.
It's my guess that you are getting asynchronous behavior when loading the script, and it's not executing until after onload. I can't recreate your problem.
You may be including your script at the top of the page. Where it gets the document.write() stuff and thus writes the text instead of a append behaviour.
The safer solution is to append a document element to the page - that should always work
Im experiencing strange behavior with Firefox and Dojo. I have a html page with these lines in the <head> section:
...
<script type="text/javascript" src="dojo.js" djconfig="parseOnLoad: true, locale: 'de'"></script>
<script type="text/javascript">
dojo.require("dojo.number");
</script>
...
Sometimes the page loads normally. But sometimes it won't. Firefox will fetch the whole html page but not render it. I see only a gray window.
After some experiments I figured out that the rendering problem has something to do with the load time of the html. Firefox starts evaluating the html page while loading it. If the page takes too long to load the above javascript will be executed BEFORE the html finishes loading.
If this happens I'll get the gray window. Advising Firefox to show me the source code of the page will display the correct complete html code. BUT: if I save the page to disk (File->Save Page As...) the html code will be truncated and the above part will look like this:
...
<script type="text/javascript" src="dojo.js" djconfig="parseOnLoad: true, locale: 'de'"></script>
<script type="text/javascript">
dojo.require("dojo.number");
</script></head><body></body></html>
This explains why I get to see a gray area. But why does this code appear there? I assume the require() method of Dojo does something "evil". But I can't figure out what. There is no write.document("</head><body></body></html>"); in the Dojo code. I checked for it.
The problem would be fixed, if I'd place the dojo.require("dojo.number"); statement in the window.load event:
<script type="text/javascript">
window.load=function() {
dojo.require("dojo.number");
}
</script>
But I'm curious why this happens. Is there a Javasctript function which forces Firefox to stop evaluating the page? Does Dojo do somethig "bad"? Can anyone explain this behavior to me?
EDIT: Dojo 1.3.1, no JS errors or warnings.
What does the rest of the page look like? What elements should be rendering that aren't? What other Javascript do you have?
What you have looks fine, but you will not be able to use methods in dojo.number or anything else loaded via dojo.require until after the page loads -- you must wait for window.onload to fire, or use the dojo.addOnLoad() method to trigger a callback. The latter is actually a bit quicker than onload.
dojo.require uses synch xhr to load which does block the browser, so if the load is unusually slow, you will notice a delay in the rendering of the page.
I think this is a rendering bug in Firefox that I've seen in a number of contexts where the one common factor is the amount of time the browser takes to load all the resources loaded in the of the page. The more scripts you have in the head that take a long time to request over the network or eval, the higher your chances are of running into this. Hitting the page with a warm cache notably reduces the possibility of running into the paint bug as well. Another way to mitigate it is to put the javascript at the end of the which is also a best practice since it doesn't block the browser from previewing markup immediately as it gets it.
Regarding the specifics of using dojo, common use cases include running things onload like creating and starting up widgets. If you have code in an onload handler that uses a dojo module like a widget, then stick the dojo.require statement inside the onload handler as well instead of before the onload handler. There's no point in suffering the performance penalty or blocking the initial UI rendering if you don't need it until later. Then build custom dojo layers to include the minimal core (possibly a custom base to make it even smaller) and the other 90% of what you need in a separate layer. Load the minimal core layer in the head (to get dojo.addOnLoad, etc) and then the other layer at the end of the body. If you live in a modular application framework where apps come and go in the page content area depending on the page you're on, each app should put the dojo.require statements for the respective dojo module it uses immediately before the module is actually referenced.
This won't work obviously if you need a module immediately in an inline script, but if that's the case then a custom dojo build will also help mitigate that case also.
I'm unaware of a reported issue with Mozilla, but I have also seen this much less often on other browsers some time ago.
Why are JS scripts usually place in the header of a document? Is it required by standards, or is it just a convention with no particular reason?
See http://developer.yahoo.com/performance/rules.html#js_bottom
Although past practice has often been to place them in the header for the sake of centralizing scripts and styles (and the like), it is advisable now to place the scripts at the bottom to improve loading speed of the rest of the page.
To quote:
The problem caused by scripts is that they block parallel downloads. The HTTP/1.1 specification suggests that browsers download no more than two components in parallel per hostname. If you serve your images from multiple hostnames, you can get more than two downloads to occur in parallel. While a script is downloading, however, the browser won't start any other downloads, even on different hostnames.
In some situations it's not easy to move scripts to the bottom. If, for example, the script uses document.write to insert part of the page's content, it can't be moved lower in the page. There might also be scoping issues. In many cases, there are ways to workaround these situations.
An alternative suggestion that often comes up is to use deferred scripts. The DEFER attribute indicates that the script does not contain document.write, and is a clue to browsers that they can continue rendering. Unfortunately, Firefox doesn't support the DEFER attribute. In Internet Explorer, the script may be deferred, but not as much as desired. If a script can be deferred, it can also be moved to the bottom of the page. That will make your web pages load faster.
A <script src="url"></script> will
block the downloading of other page
components until the script has been
fetched, compiled, and executed. It is
better to call for the script as late
as possible, so that the loading of
images and other components will not
be delayed.
It depends on what the script is doing. If your code is wrapped in onLoad event then it doesn't matter since it will return almost immediately and not block otherwise you should put it where it fits because the placement does matter.
As for putting it at the end, it does give a little extra time for user to start looking at the page. Just ask yourself a question - does my site work without javascript? If it doesn't, then in my opinion it doesn't mater where you put it since onLoad code will only be executed when the DOM has been fully loaded (that includes binary content like images). If you can use it without javascript then put it at the end so that images can load faster.
Also note that most JS libraries use special code which works around the onLoad problem and uses custom event for this which gets fired once DOM has loaded and doesn't wait for binary data.
Now that I wrote all that, I got a question of my own. Does using say jQuery's
$(document).ready(function () {});
and putting the script tag at the end of page is the same as using onLoad event and putting it at the start?
It should be the same because browser would load all images before loading the script which is the last one in the list. If you know the answer leave a comment (I'm too lazy and it's too late to test it atm).
It's just a convention. It's usually recommended to put scripts at the end of the body so the page can display before loading them, which is always a plus. Also, document.body can't be used until the document is loaded or if you put the script in the body.