Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

If we assume all web browsers understand the <script> defer attribute, is it better just to put the linked script in the head with the defer?

If we compare these two options for a webpage and linked JavaScript files:

  1. putting all <script src="..."> near the end of the webpage, versus
  2. putting them in the <head> section but use <script defer src="...">

and if the mechanism of how defer works is as described in this page, this other page, on Mozilla, and that defer is supported in almost all modern browsers, then isn't it just better to use Option #2 above?

The reason is, Option 1 and 2 would work exactly the same, except for Option #2, the download of the JavaScript file can be parallel with the parsing (and rendering) of the HTML file. So if the download time is 0.2s or 0.5s, this time could be saved. This is true for SPA (Single Page Application) or for old fashion webpages if the JS adds elements to the page or kick-starts any dynamic or interactive elements in the page.

The only exception would be, if the browser is smart enough that, before parsing the whole HTML file in Option 1 above, it already "gathers" all JS file URLs and silently download them before the HTML file is parsed to the end or to the point of the <script> tag. But this will make Option 1 and 2 work exactly the same, so Option 2 would still be faster for browsers that doesn't do this?

P.S. having said that, I think there is one catch: since HTTP/1.1 specification recommends browsers should download at most 2 items from the same hostname at a time, so if the JS file is being downloaded and taking up one spot, some image files can be slower to arrive. (if the JS and images come from the same hostname)

like image 245
nonopolarity Avatar asked Dec 13 '19 04:12

nonopolarity


1 Answers

You’ve spotted the problem in your last paragraph.

In terms of JavaScript execution putting defer scripts in head or at bottom has little difference (though it’s different for async scripts). However do be aware that defer scripts execute in order so any other defer script in middle of the page will execute after defer scripts in the head and before defer scripts at the bottom of the page. Usually when using defer you don’t care about the execution time but if there are dependencies then ordering can be important (i.e. loading jQuery before a script that needs jQuery) and defer honours ordering (where as async does not).

But yes downloads will cause other elements to suffer. Yes the spec recommends two connections are most, but in reality most browsers use 6 connections for HTTP/1.1. This means if your low-priority, defer scripts are using one of those there’s only 5 connections left for everything else on that page. It is likely there are higher priority resources on the page than defer scripts so this is wasteful.

Browsers will scan ahead in the HTML to get a list of all the resources, and assign a priority to each resource (which will be low for defer scripts) but at the same time the browser will start taking items off the top of this prioritised queue and a low-priority defer script in the head may be started on before the other resources are seen. And because of this “preload scanner”, any benefit of putting defer scripts in the head is minimal. The browser will still see it and request it when it can. Yes it’ll take slightly longer to see it when at the bottom (particularly for large pages that might take a while to fully download) but it’ll still see it as soon as the HTML is downloaded in its entirety, even if it’s still processing scripts and other resources on the page so hasn’t got to the end of the HTML.

In an HTTP/2 world, where there is not 6-connection limit you may think this doesn’t matter as much, but it often does. Partly because the connection limit is not completely unlimited (100 or 128 parallel streams are common limits on HTTP/2 servers) but more so because bandwidth is not completely unlimited and so download contention is a real thing. HTTP/2 has the concept of prioritisation so in theory should be able to handle this well, but in practice HTTP/2 prioritisation is often poorly implemented on servers and surrounding infrastructure that you can’t depend on this.

Patrick Meenan has an awesome talk about how browsers load resources, particularly touching on the HTTP/2 issues. Well worth a watch if interested in this sort of thing.

So, in summary, I would still keep defer scripts to the bottom of the page for now.

like image 90
Barry Pollard Avatar answered Nov 14 '22 20:11

Barry Pollard