2

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.

Mogsdad
  • 44,709
  • 21
  • 151
  • 275
  • You need to go and re-read your quote. To make it clear I'll bold what you appear to be missing here: *"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 are trying to prove a claim that was never made. You mention *"It can be the case, but not necessarily"*, which is literally what the quote just said. – Spencer Wieczorek Oct 31 '17 at 19:59
  • it's nice to be right, but it's more right to be nice. i don't see any problem with google's explanation, not do i get the complaint. perhaps it could be more explicit, but i don't think it's wrong, at all. also, did you know a defer'd tag can fire 5 mins after page load and still be within design specs? It fires when it arrives. All defer should be taken to mean is that it won't _halt_ the rendering of the page, which means you can't use `document.write()` and so on. – dandavis Oct 31 '17 at 20:09
  • @Spencer Wieczorek I also considered they meant it like that, but then i don't understand why they don't come with for example a "disable caching" solution, because as you can see in the example, it will render 5 seconds earlier in case of no caching. So there are situations where a solution like that could speed up rendering. – Maarten Bruins Oct 31 '17 at 20:14
  • @dandavivs You are also saying: "that it won't halt the rendering of the page". Just see my example and you will see that it will halt the rendering of the page. So apparently it's confusing, because otherwise you would not say that. – Maarten Bruins Oct 31 '17 at 20:17
  • @Spencer Wieczorek I was reading it again and again, but i'm reading it as followes. The word "MAY" i see like that you COULD use defer. Later on they are also saying "Doing so". Other documentation confirms they mean it like that, but i have to search for it again, so i'll come back to it. – Maarten Bruins Oct 31 '17 at 20:31
  • @Spencer Wieczorek For example here: https://www.html5rocks.com/en/tutorials/speed/script-loading/#disqus_thread they are saying: "Scripts that are dynamically created and added to the document are async by default, they don’t block rendering and execute as soon as they download" And in that whole article they are talking about using async or defer to avoid "blocking render". Script execution is always blocking rendering, so this quote is also not correct in my opinion. – Maarten Bruins Oct 31 '17 at 20:35
  • @Spencer Wieczorek I know for sure that they meant it like that, because the article is about: "Remove Render-Blocking JavaScript" and they give defer as solution. But with defer it's still render-blocking or at least it can be, so that's not removing. So they are wrong anyway in my opinion. From Dandavivs comment you see he also thought it's not render blocking anymore with defer. So people are not just wrong out of nothing and that's exactly my point. – Maarten Bruins Oct 31 '17 at 20:43
  • @dandavis If i had to choose between right or nice then i would choose to be right. And i'm not doing it for myself, but for people like you. I see you are Professional web developer and probably already many years. Nowadays rendering and speed of a website are one of the most important things. And from your comment i can see you don't understand it. That's not your fault, because i was thinking the same before i dived into it, but that's why Google needs to do something about it in my opinion. Sorry i can not put everything in 1 comment, but that's because of the maximum number of characters. – Maarten Bruins Oct 31 '17 at 21:04
  • @MaartenB. no, it's talking about pausing rendering for the _loading_ of a script. you hammering the CPU has nothing to do with that load strategy. Further complicating the issue in modern browsers is that they fetch all scripts in parallel; if you go back a few years, you would see stair-step script loading in the network tab. A script with defer would cause the chart to show a two-high step, as two tags load at once instead of just one. The effects w/todays smarter fetching are more muted, and again, only practically apply to `document.write()` afaik. – dandavis Oct 31 '17 at 21:14
  • but the bottom line is that _defer_ just _allows_ a delay, it doesn't _guarantee_ one. if the script is loaded and the browser's not doing anything, it very well can fire before the doc is complete, even if that's not typical. to me the article is relatively clear, you're just picking a fight over semantics. – dandavis Oct 31 '17 at 21:19
  • @dandavis I know it's about that (no need to explain it to me), so that's why you can not say: "that it won't halt the rendering of the page". They can not use the term "Remove Render-Blocking JavaScript" in an article like that. They have to use something like "Remove Render-Blocking (down)loads". And it's not only about words / semantics, because see my example. The difference is 5 seconds! So that could be a reason to disable caching of script.js, because then the example is rendering much faster. – Maarten Bruins Oct 31 '17 at 21:26
  • @dandavis And can you be more specific with: "fire before the doc is complete". What do you mean, DomContentloaded / LOAD / done html parsing / done rendering? But the bottom line is that i can make a big difference (see my example), so it's not only about semantics. – Maarten Bruins Oct 31 '17 at 21:32
  • @dandavis And it's not a fight over semantics anyway. I will try to make it more clear with the following metaphor. Google is actually saying: i'm gonna avoid that the sun shines (render blocking javascript). Then they will take you to the night and they are saying: now we avoided that the sun is shining (defer). That's incorrect, because the sun is "always" shining. That's why it's not only semantics, but also really incorrect. – Maarten Bruins Oct 31 '17 at 21:36

1 Answers1

0

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

enter image description here

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)

Community
  • 1
  • 1
Spencer Wieczorek
  • 21,229
  • 7
  • 44
  • 54
  • Now we are at least talking ;), thanks! I have some thinking about it, but first before giving a reply, i want to have some more things clear from you, so i know how you mean it. What is your definition of load and how is that related to download? But my point is anyway also that they start to talk about "defer" as a solution for avoiding "Render blocking Javascript". Then they had to say "Render blocking loading". You can see my metaphor about that in the comments of the question on this page. Anyway i will repeat it for you in my next comment. – Maarten Bruins Nov 01 '17 at 15:37
  • This is the metaphor: Google is actually saying: i'm gonna avoid that the sun shines / burns (render blocking javascript). Then they will take you to the night and they are saying: now we avoided that the sun is shining / burning (defer). That's incorrect, because the sun is "always" shining / burning. So it's really also incorrect if you would ask me. You can not avoid something that is anyway always the case. – Maarten Bruins Nov 01 '17 at 15:39
  • So you want make from it: "The loading of scripts are being deffered until after the initial render". In my example the html is part of the initial render and downloading script.js must be finished before the initial render, because the execution, is blocking it in my example. That's not possible if it has not been downloaded yet. Or do i get you wrong? – Maarten Bruins Nov 01 '17 at 15:57
  • And you're saying the term "Render blocking Javascript", is referring to: et cetera. I know where it's referring to, but then the term itself can be wrong. Javascript != Javascript loading ... an apple is fruit, but fruit is not an apple. – Maarten Bruins Nov 01 '17 at 16:00
  • @MaartenB. It means after that source has been downloaded and can be executed, like if you downloaded a file and you cannot run it until it was fully downloaded. In regards to your metaphor yes JavaScript execution will always render block (*sun is always shining*). Although the term *"Remove Render blocking Javascript"* is really referring to the JavaScript files themselves and how they are loaded, rather than that there is executing JavaScript that does not block rendering (*which isn't true*). – Spencer Wieczorek Nov 01 '17 at 16:00
  • @MaartenB. All executing JavaScript is *"Rendering Blocking JavaScript"*. Also JavaScript can be referred as the JavaScript File itself. Also yes basically the only reason why it "Removes" it is because the page has already loaded and rendered before the JS File has finished download, and hence did not execute yet. – Spencer Wieczorek Nov 01 '17 at 16:03
  • Javascript could be: downloading, reading (otherwise hoisting would not exist), executing. So Javascript is fruit and executing is the apple. An apple can also refer to fruit, but it's not the same. But you have changed the quote to: "The loading of scripts" and then "deferred until after the initial render". The loading will not take place after the initial render in my example, so that quote can also not be correct, right? – Maarten Bruins Nov 01 '17 at 16:09
  • By the way, here are more examples where they are confusing terms with each other. So it's not only a one time mistake, because that always can happen: https://stackoverflow.com/questions/47058267/consequences-javascript-can-have-document-write-in-the-code https://stackoverflow.com/questions/47056269/scripts-that-are-dynamically-created-dont-block-rendering https://stackoverflow.com/questions/46979465/loading-external-javascript-via-async-script-tag-at-the-end-of-a-webpage – Maarten Bruins Nov 01 '17 at 16:25
  • @MaartenB.By Your example is separate from this, it's simply saying for scripts not needed for the initial render *may* be deferred. Means for scripts that have not finished loading yet when the initial render has already happened, since your script has already loaded before the initial render it doesn't apply here. The quote isn't making the claim about the functionality of `defer` that you are stating is wrong. Your not wrong here, but your argument isn't based on what the quote is actually saying. Rather you are using it as context and making an assumption that isn't implied. – Spencer Wieczorek Nov 01 '17 at 16:58
  • But the loading anyway happens in parallel (async or defer), so i don't see any reason to defer something that is already happening in parallel. If it would be only about the loading then there would be no difference between async and defer? But there is. If i had to make defer, i would start executing with the script, after "rendering the page" would be done. That makes also more sence. Downloading will just happen in parallel, same as with async. – Maarten Bruins Nov 01 '17 at 17:00
  • @MaartenB. Both `async` and `defer` function very similarly, the difference is that: [*"defer does the same thing, except claims to guarantee that scripts execute in the order they were specified on the page"*](https://stackoverflow.com/a/10731231/3149020). In many cases they can function in the same way, although it should be used if there are dependencies between separate files. – Spencer Wieczorek Nov 01 '17 at 17:04
  • And if the whole page already has been rendered before script.js would be done with downloading ... then there is anyway no need to use async or defer, because it's anyway not blocking rendering. So for what you will use defer in a case like that? – Maarten Bruins Nov 01 '17 at 17:05
  • That's Correct, but say you had several scripts and you needed them to be executed in the order you defined on the page to run correctly. Even if they all finished loaded after the page render. – Spencer Wieczorek Nov 01 '17 at 17:11
  • So first you're saying the "quote" what we are talking about is separate from my example. And then you're giving another situation, but defer has no effect on that!? For the order you could also just use sync in case the file already has been downloaded before. – Maarten Bruins Nov 01 '17 at 17:17
  • They are a bit similar, but with 1 big difference and that is: deferred scripts will be executed after the document has finished parsing. Anyway if i would be the maker of "defer", i would make from "has finished parsing" this: "has finished rendering". But that's a different discussion. – Maarten Bruins Nov 01 '17 at 17:17
  • @MaartenB. It does have an effect, as mentioned in the quote the effect is just for better performance. Note, all these examples are really just performance recommendations. In my opinion the title for that section *"Remove Render-Blocking JavaScript"* isn't exactly the best fit. – Spencer Wieczorek Nov 01 '17 at 17:25
  • I don't get you or you don't get me, but we'll find out ;). I just needed some time to think. I'm thinking of how i have to see your quote: "The loading of scripts > deferred until after the initial render" Also when you're having 2 files, both downloads are not blocking rendering, so they have to mean "loading and execution" together (and that's wrong). Actually they have to say only execution, because the execution will be deferred, but the download will starts anyway as fast as possible. With defer you are not deferring the downloads at all (same behavior as with sync) – Maarten Bruins Nov 01 '17 at 17:54
  • @MaartenB It's that if you didn't have `defer` or `async` it blocks the parser from continuing through the DOM. In turn a long JavaScript external file download would "block" rendering (*due to the parser being blocked*) if you didn't used those items. You actually are deferring the downloads, but just until the parser finishes. – Spencer Wieczorek Nov 01 '17 at 18:13
  • I know that and i'm aware of that. But that's not the "main catch". I will ask you a question to check about the "main catch". If you would have 2 sync script tags, just before the end of the body tag. What will be the difference in the result if you will add defer to the scripts? Anyway they are not blocking the DOM. So why you would add defer in a case like that? ;) – Maarten Bruins Nov 01 '17 at 18:24
  • Even at the bottom of the `` when you don't have `defer`, it will still block the parser when it hits that and not render yet since the parser isn't technically done. So it will wait to render (*even though there are only the ` – Spencer Wieczorek Nov 01 '17 at 18:37
  • That's right, but the script tag (and the end of the body / html tag) don't have any influence on what you will see on your screen (rendering). So in terms of rendering it does not make any sence / difference. And defer is invented to avoid "Render-Blocking javascript", but the script tag et cetera are anyway not "render blocking". They are, but there is nothing to render anymore in this case. So i think here you're going wrong. – Maarten Bruins Nov 01 '17 at 18:45
  • Yes it doesn't have any effect on what you will see, but the parser doesn't *know* that since it's not technically not done going through the HTML. If you don't have `defer` or `async` then those `script` tags *are* rendering blocking *because* the parser is blocked on those tags. It then will not finish with parsing the DOM until those resources loaded. – Spencer Wieczorek Nov 01 '17 at 19:08
  • But we know it's the end of the document, so the whole document is already on the screen. So the question from me to you will stay: why you would use defer if at the end there is not really a difference in terms of "render speed"? – Maarten Bruins Nov 01 '17 at 19:08
  • @MaartenB. Because there *is* a difference. An HTML parser will go and parse the page line-by-line, only after it completely parsed the entire structure will rendering ever happen. for a normal ` – Spencer Wieczorek Nov 01 '17 at 19:11
  • Are you saying now that a page will not show / render anything before the page has been completely parsed??? Because you can not say that. – Maarten Bruins Nov 01 '17 at 19:13
  • No that's not how it works. Then why google is talking about rendering in combination with above the fold and under the fold. That's because the browser first can show / render things above the fold and later on under the fold. I'll make an example to show you that it's working like that. Give me one moment. – Maarten Bruins Nov 01 '17 at 19:17
  • @MaartenB. *"External blocking scripts force the browser to wait for the JavaScript to be fetched, which may add one or more network roundtrips before the page can be rendered."* – Spencer Wieczorek Nov 01 '17 at 19:24
  • @ Spencer Wieczorek But with "the page" they don't mean "the whole page". When i was reading that for the first time i was anyway frustrated, because i thought it's for sure really confusing for people. I did some tests after reading it to find out that they did not mean "the whole page".Soon i'll make an example for you to show it. – Maarten Bruins Nov 01 '17 at 19:29
  • https://external-blocking-scripts-1.glitch.me/ https://external-blocking-scripts-2.glitch.me/ Voila, one with internal javascript and one with external javascript. If the browser would only show / render something after about 30 seconds then you would be right, because then the whole page is completely parsed. But it will show already some content much earlier. – Maarten Bruins Nov 01 '17 at 19:41
  • @MaartenB. Sorry that's my bad, I miss interpreted what you meant when you asking for clarification. Yes your correct there; what I was really trying to say is that it still technically rendering blocking even if you don't need to render anything else. I didn't mean "the whole page" is blocked, just the current structure (*meant to say element here*) that it's parsing. – Spencer Wieczorek Nov 01 '17 at 19:51
  • Yeah i am aware of that, but for the result (or pagespeed), it does not chance anything, so you're right by saying that, but that would not be a reason to use defer. So my question for you still stays the same. You're not gonna use defer if you know it will actually don't change anything. In theory it will chance a bit, but in practise it will not chance anything. So that's not the reason i'm searching for... – Maarten Bruins Nov 01 '17 at 19:57
  • Then yes, while there is technically a "difference", (*assuming that `script` doesn't have any DOM manipulations*) there isn't really a render speed difference in that case since there isn't anything new to render. – Spencer Wieczorek Nov 01 '17 at 20:04
  • But defer is made for scripts that doesn't have any DOM manipulations, so that's not the problem. So then the question is ... for what kind of cases you need to use defer theoretically? I'm saying theoretically, because in practise defer works differently, because browsers are not consistent in using defer. – Maarten Bruins Nov 01 '17 at 20:20
  • Okay i'll not let you think too much. For new browsers it does not matter to use defer or just sync. But some older browsers don't have "prescanners", scanning for downloads. So in a case like that it's useful to put the script tag at the beginning of the document and put "defer" on it. That's the whole reason why they invented "defer". So the main thing is not the order of files like you were saying (because with sync you can also do that). The main "catch" of defer are older browsers and it's about that they can start earlier with downloading. – Maarten Bruins Nov 01 '17 at 20:54
  • So now we can come back to the main issue here. Placing the script tag (with defer) at the beginning of the document or at the end of the document, does not make really difference in newer browsers. I could also do the same test with my defer script tag at the beginning of the document and then i would get the same result. The execution will be deferred until "html parsing" is done, but that does not have to mean that the rendering is done. So you have changed the quote, but it does not make sence like that. – Maarten Bruins Nov 01 '17 at 21:00
  • I went ahead and removed that since it wasn't much help. I'd agree that it would be better if it said something like : *"The loading and execution of scripts that are not necessary for the initial page render may be deferred until after the DOM is parsed."*. That said their quote is not technically incorrect as I've said before. – Spencer Wieczorek Nov 01 '17 at 21:40
  • Part 1: @Spencer Wieczorek I still disagree ;). With "defer" on a script tag you want to defer the execution of some javascript to a certain moment in time / place. It's not about what will or can be the case, but it's about what you want to achieve with defer. I will use a metaphor again to make it more clear to you. Imagine we are having every day an appointment at 13:55. We will find out that every day there is a bomb explosion at 13:59. So we will say to to each other: becuase of that we need to defer our appointment after 13:59, so 14:00. – Maarten Bruins Nov 01 '17 at 22:24
  • Part 2: @Spencer Wieczorek It can happen that we will be a bit late one day and that we will be there 14:05, but usually we're there around 14:00. Anyway it means that we defer it until 14:00. You can not say: we defer the appointment to 14:05, because then it's not possible to meet around 14:00. But vice versa we can say we deferred the appointment until 14:00 and meet each other around 14:05. – Maarten Bruins Nov 01 '17 at 22:24
  • Part 3: @Spencer Wieczorek So that's the big difference and that's why it's really incorrect. If you are not "on my side" after this metaphor i don't know it anymore. More clear i can not explain it to you. Technically the quote is also incorrect. If we deffer our appointment until 14:05, we can not meet around 14:00. And 14:05 = done rendering and 14:00 = done parsing html. So they can not use "until after the initial render". This has to be "until after parsing html". – Maarten Bruins Nov 01 '17 at 22:24
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/158028/discussion-between-spencer-wieczorek-and-maarten-b). – Spencer Wieczorek Nov 01 '17 at 23:08
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/158102/discussion-between-maarten-bruins-and-spencer-wieczorek). – Maarten Bruins Nov 02 '17 at 19:01