When executing a jquery $.get() call to retrieve an html file that includes a script tag with a src attribute, I am getting the warning "Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience." in Firefox's console. Here is some simple code that I used to narrow down the warning that demonstrates this:
foo.html
<html>
<head>
<script src="http://code.jquery.com/jquery-1.11.2.js"></script>
</head>
<body>
<script>$.get("bar.html", function(data) { $('#testdiv').html(data);});</script>
<div id="testdiv"></div>
</body>
</html>
bar.html
<script src="foo.js"></script>
Note that foo.js is empty, so nothing in there seems to be causing the warning. I don't understand the reason for this. Would anybody know what's causing this?
I started to wholly investigate this issue myself and the warning is being generated by your browser when JQuery dynamically loads a page that contains a script tag with a reference to an external script.
So, in your case, foo.html loads bar.html and as your browser begins to parse the content from bar.html it encounters <script src="foo.js"></script> which causes the browser to stop parsing content, load and execute foo.js. If you don't have any code in foo.js, you won't notice any detriments to performance, but if your browser takes any discernible amount of time to parse and execute foo.js then your end user will actually lose control of the browser (meaning the browser will appear to be frozen) until foo.js finishes executing. This is what is meant by the warning's message: detrimental effects to the end user's experience.
The work around that I am considering is to implement custom events to trigger the relevant pieces of my code at the proper time which is probably a better idea to begin with. I am curious to know if anyone else has any clever ways of circumventing the issue.
Related
In this post:
Why google is using the term "Render-Blocking JavaScript"?
#jaffa-the-cake is asking in a comment to someone:
"Which piece of documentation do you consider incorrect?"
Let's take for example this documentation:
https://developers.google.com/speed/docs/insights/BlockingJS
And now let's take for example what they are saying about "defer":
The loading and execution of scripts that are not necessary for the initial page render may be deferred until after the initial render or other critical parts of the page have finished loading. Doing so can help reduce resource contention and improve performance.
Note that the article is about "Remove Render-Blocking JavaScript", so with the word "may" they mean that you COULD use defer.
With "defer" on a script tag, you will NOT defer "the execution until after the initial render of the page have finished loading". It can be the case, but not necessarily.
"Defer" will defer the execution until after the initial html is in the DOM, but that's something different than "render". The execution will take place after the (preceding) html is in the DOM and before DOMContentLoaded, but that does not mean: "render of the page have finished loading". It would be correct if they would use the term "html parsing of the page have finished".
An example which confirms the theory of above:
INDEX.HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Test</title>
</head>
<body>
Some HTML line and this is above the fold
<script src="script.js" defer></script>
</body>
</html>
SCRIPT.JS (from cache!)
// Synchronous delay of 5 seconds
var timeWhile = new Date().getTime();
while( new Date().getTime() - timeWhile < 5000 );
In case the browser will take script.js from cache then "Some HTML line and this is above the fold" will be shown AFTER 5 seconds! So that means the initial render of the page have NOT finished loading yet (while using defer). So in my opinion that means the documentation is incorrect.
p.s. Without script.js from the cache, a browser will have time to finish rendering of the preceding html. The file script.js first has to be downloaded, so that's what gives the browser extra time. With caching, there is less time between "done parsing html" and starting with the "javascript execution", so then there is a chance that "javascript execution" already starts before "finishing rendering of the preceding html". So in case of speed gain, you could even consider in this example to disable caching, so the rendering of the preceding html will be faster.
I have a lot more tests / examples which proves other parts in other documentation (about rendering) of Google are incorrect (in my opinion), but i will keep it clear in this post by using 1 example.
If you are disagree with me, please don't give only a negative reputation, but at least give a comment why you think it's incorrect and which test you did to confirm it. I'm already trying to convince some people at Google that they are incorrect in my opinion, but they are kind of offended by that. Of course i would not say that they are incorrect if i didn't put a lot of time / energy / testing in it and if i would be pretty sure about it. Until now they are saying to me: "consider that the misunderstanding may be yours", so i feel like a small boy "fighting" against a big wall. For me it's not about to get right in the first place, but i see so many people around me (they are already for many years working in IT) struggling with the subject rendering and i can understand it, because the documentation about it is very confusing. That's also why i dived deeper into it, because it was also getting too confusing for me, so i wanted to understand it better.
And if i am wrong, just convince me with arguments and i am the first who will say i was wrong.
After re-reading your question and the linked quote I'm seeing where you are coming from, and why this quote can be misleading. For reference let me put the quote below with the title included:
Defer loading of JavaScript
The loading and execution of scripts that are not necessary for the initial page render may be deferred until after the initial render or other critical parts of the page have finished loading. Doing so can help reduce resource contention and improve performance.
You already understand this, but I'll link it for a reference on how defer works.
As you mentioned, yes the execution of JavaScript in defer and in general is always render blocking, and rather defer does not block the DOM parser.
The reason why the quote is misleading/confusing is because of the sections in bold:
The loading and execution of scripts that are not necessary for the initial page render may be deferred until after the initial render or other critical parts of the page have finished loading. Doing so can help reduce resource contention and improve performance.
The section "The loading and execution of scripts that are not necessary for the initial page render may be deferred until after the initial render". While not an incorrect statement, is misleading because but the performance gain is really directly due to the parser not getting blocked.
This can be clearly shown using the official documentation on defer
A more direct and more clear way to describe this would be as you mentioned:
The loading and execution of scripts that are not necessary for the initial page render may be deferred until after the initial parsing or other critical parts of the page have finished loading. Doing so can help reduce resource contention and improve performance.
That makes it clear that the performance gain is due to the parser being deferred. It also is more inline with how defer specs describe it and the befits of defer:
If the async attribute is not present but the defer attribute is present, then the classic script will be fetched in parallel and evaluated when the page has finished parsing. If neither attribute is present, then the script is fetched and evaluated immediately, blocking parsing until these are both complete. (W3C)
We have a web application that renders HTML pages and includes some external JavaScript files which define variables like jQuery, $, app etc.
We track client-side JavaScript errors in Bugsnag and sometimes we receive errors like Uncaught ReferenceError: $ is not defined or ReferenceError: Can't find variable: app.
What could be possible causes behind this? Two that I can guess are: user might have clicked "Stop" in browser and JS files didn't completely load but inline JavaScript within page was still executed (is that possible?), or some JavaScript files were blocked by a browser plugin/extension.
We have observed it happening in all major browsers (Firefox/Chrome/Safari etc.), but its occurrence is quite rare - usually once in thousands of requests.
Here is the excerpt from page:
<script src="https://path/to/jquery.js"></script>
<script src="/path/to/app.js"></script>
<script type="text/javascript">
$(document).ready(function() { ... });
// ^^^^ I receive the error here
app.init(function() { ... });
// ^^^^ and sometimes I receive the error here
</script>
One plausible explanation is that certain browser extension is blocking those scripts from loading (e.g., an ad blocker).
I am forced to use a web application written (over a decade ago I'm guessing) for IE6 and only works with IE (newer versions in quirks mode). I have been able to repair some of the more egregious javascript with a Safari extension that injects scripts to detach event handlers and replace them with DOM compliant versions.
I am now turning my attention to annoyances rather than the downright broken. The heavy handed use of alerts to inform the user of progress is painful. I thought it would be a fairly nice addition to my extension to override the window.alert function with some css popovers, but the challenge I am having is with pages that are sent back after an http post, where the first thing they do is display a success (or failure) alert.
According to this Apple documentation "a Start Script executes when the document has been created but before the webpage has been parsed". I would have thought that if the page hadn't been parsed, the scripts in the page's body's script tags wouldn't run, but this is not the behaviour I am seeing. Instead, it appears that any scripts in the page returned from the post response execute before my start script even loads.
To test this I have a very simple start script that logs to the console location.href and tries to replace window.alert with console.log.
The injected start script:
console.log(window.location.href + "loaded killAlert.js") ;
window.alert=function(str) { console.log(str) ; }
The test web page:
<html><head></head>
<body>
<script>alert("this is an alert message") ;</script>
nothing to see here... move along.
</body>
</html>
What happens is that when loading a test page with a script embedded, the alert executes before anything is written to console.log.
My questions—
When do start scripts actually get called?
Is there any way I can get them to execute before any scripts on the page?
While this seems like it should be fairly straight forward, but so far I haven't been able to find a way around the problem through reading documentation, search or experimenting. I'm hoping someone else has solved something similar.
<head>
<script>
(function() {
console.log(window.location.href + "loaded killAlert.js") ;
window.alert=function(str) { console.log(str) ; }
})();
</script>
</head>
Try calling it anonymously, it will execute the script immediately after the creation. Hope it helps.
I am trying to figure out a problem with some code I have inherited.
I have an HTML page with
<script type="text/javascript" src="file1.js" defer="defer"></script>
<script type="text/javascript" src="file2.js" defer="defer"></script>
</body>
</html>
file1.js has
FOO = {
init : function () {
var bar = BAR;
}
}
$(document).ready(FOO.init);
file2.js has
var BAR = {
}
Because of the defer attribute on the elements, is it safe to assume that when the .ready() calls FOO.init() that BAR may still be undefined at that point b/c the code in file2.js hasn't executed yet because of the deferred execution?
This would match a bug I am trying to track down (only occurs sporadically in IE), but I really want to understand why this is happening before I work on a solution. I have no idea why the original developer used defer, other than a cryptic commend about "he had to" do it this way.
Defer should cause the script to be added to a queue that is processed after the page is completely loaded. According to the spec deferred scripts should be added to the queue in the order they came onto the page.
However different browsers have done slightly different things with the order. IE seems to run defer scripts in the order they finished loading rather than the order they occurred on the page. So you seeing the error sporadically because sometimes it's loading them in the right order and sometimes not.
See this post on hacks.mozilla.com for a more exhaustive explanation and examples of how different browsers handle the ordering of the defer queue.
Deffering in javascript gives preference to the browser of when to interpret the script, in some optimal conditions like with chrome the script is downloaded while the page is being loaded then parsed and interpreted. If you use defer like the above you can never be certain which script is loaded first or when the interpretation is complete.
BAR could be undefined on one page load and be defined on the reload (cached) or the second script was loaded first.
To test this try make a change to one of the scripts to force a new download and interpretation and see what race conditions exist.
I ask because I'm running an application in which I load an external script file in the HEAD section of the page, and then attempt to call a function from it in the onLoad section of the BODY tag.
external.js
function someFunction()
{
alert("Some message");
}
myPage.html
<html>
<head>
<script type="text/javascript" language="javascript" src="external.js"></script>
</head>
<body onLoad="someFunction();">
</body>
</html>
Using the developer tools in IE8, I get an exception thrown at the onLoad statement because, apparently, the external javascript file hasn't been loaded yet.
I haven't had this problem come up in IE7 before, thus my question.
Did they change the load order between IE7 and IE8? If so, is there a better way to do this? (the real function references many other functions and constants, which look much better in an external file)
Thanks,
B.J.
Well, I feel pretty stupid actually.
Turns out the problem wasn't with the load order. The problem was that the external javascript file had a syntax error in one of its functions, and apparently when the exception was thrown it completely invalidated the whole file, thus making the rest of the functions unavailable to the main page.
I'm not sure if this behavior is different in IE8 compared to IE7, but anyway, that was the real problem.
Thanks for your reply.
B.J.
I doubt very much that his has changed it would break a considerable number of websites.
Try this (without using the developer tools):-
<body onload="alert(somefunction)">
this shouldn't break and will tell you whether at the point onload executes whether the identifier somefunction can be seen.
Assuming that what you think is happening is what is happening, you should try to attach the body.onLoad later on.
To simplify things, you can do it with Prototype (including prototype, of course) with
Event.observe(window, 'load', function() { myFunction.init() });
or JQuery (including JQuery) with
$(document).ready(function(){
// Your code here...
});
I think there is a pure Javascript way to do this, but the problem is that the body element won't exist yet, so it's rough...
That said, I have had no problems running body onload in Javascript with IE8, and putting it right into the body tag, using external files. I'm going to test that right now out of curiosity, and I'll report back.
Edit: There's no problem doing the onload from an external file. However, while we're at it, you might want to get to know JQuery, Prototype or Scriptaculous :)