Load a script synchronously before render (programatically in <head>) - javascript

I have a javascript script that I want to load synchronously, but the URL of the script is determined by the value of a cookie. For example:
<script src="/js/[user-id-from-cookie].js">
This script has to load in the <head> of my HTML document and must be run synchronously (it has to block the main thread while it is downloaded and executed).
How can I use javascript to:
Read the value of a cookie
Download and execute the script synchronously
I need to do this in pure javascript, no frameworks like jQuery etc.
Thanks!

You can use document.write to load scripts synchronously.
But use it this way may cause some lag, I'd like to offer some alternatives.
parse the cookie and return different script per user by server. (recommended, but need to have server support)
load all the script, but rewrite them so only one would execute based on condition. (not good for large amount of variant, of course)
hide the body and only show after whatever preprocess have done. (not actually how to load script, but then you can load it asynchronously)

Related

Javascript async defer order of execution in case of multiple files in Single Page Applications

I am trying to improve the page load performance of my page, that is implemented on EmberJS.
I am considering using asyc and defer on our Javascript files. All other optimizations have already been done (moving the scripts to the bottom of the page, adding async and defer to analytics tags etc).
Now, as per ember-cli specs, the generated index.html has two script tags - one vendor JS file and one application JS file.
If I am to implement async and defer, I need to ensure that my vendor JS file is loaded before my application JS file, to make sure the latter has all required code to initialize the application.
I understand that the order in which the scripts are fetched and parsed are different when defined with async and defer, as defined here
My question is this:
If you have multiple JS files in the same page, is there a way to fetch and execute them in a stipulated order? I'm looking for something like callbacks/promises in async requests, but in terms of the actual script tag itself.
Things may have changed for the better since this question was first posted, but it seems that in 2019 you can defer your scripts and have them processed in the order the script tags are written in your html document. Adding defer to both your vendor script and your main script will cause them to load in parallel, not block parsing of the html document, and be processed in order on document parse completion.
The 4.12.1.1 Processing model section of whatwg's scripting document goes into quite a bit of detail that I'll try to summarise here:
If the script's type is "classic" (not type="module"), and the element has a src attribute, and the element has a defer attribute, and the element has been flagged as "parser-inserted", and the element does not have an async attribute
then add the element to the end of the list of scripts that will
execute in order as soon as possible associated with the node
document of the script element at the time the prepare a script
algorithm started.
Check out the link for full details, but essentially what it seems to be saying is that deferred scripts will be processed in the order they are parsed in the html document.
MDN agrees:
Scripts with the defer attribute will execute in the order in which
they appear in the document.
One other important point to note (from the same MDN document):
Scripts with the defer attribute will prevent the DOMContentLoaded event from firing until the script has loaded and finished evaluating.
It's also worth noting that neither whatwg nor MDN says anything about placing your script tag in the head or at the bottom of the body of the html document. If all of your scripts have the defer attribute, they will be processed in occurrence order when the html document has completed parsing. Putting the script tags in the header will mean they will start to download early in the html document parsing process, rather than later which is the case when they are placed at the bottom of the body. But of course that also depends on how many other resources you are downloading from the same host in parallel.
Rambling a bit now, but in summary, for best non-blocking performance:
Place all your script tags as early in the html document as possible
Add them in the order that you want them to be processed
Add the defer attribute to all of them (if they don't need to be processed synchronously or as soon as downloaded)
For scripts that need to be processed as soon as downloaded, add the async attribute. HTML parsing will continue while the script is downloading - will pause when the script has finished downloading and while the script is executed - and will resume once the script has finished executing.
For scripts that need to be processed as soon as downloaded, and that have side effects such as modifying the DOM, don't add async or defer. HTML parsing will pause while the script is downloading - will stay paused when the script has finished downloading and while the script is executed - and will resume once the script has finished executing.
Update July 2020:
In Chrome, downloading and parsing of synchronous scripts (those without async or defer) has improved quite a bit. Downloading and parsing are done on separate threads - and the download thread streams the file into the parser as it downloads.
In combination with <link rel="preload"> in your <head>, it's possible that your file could be downloaded by the time the HTML parser reaches your <script> tag - which means it won't need to pause and can execute the script right away:
The image above is taken from the video Day 2: Chrome web.dev Live 2020 - What's New in V8 / Javascript - the section in which they explain updates to downloading and parsing is about 4 minutes long, but well worth the watch.
I can think of two approaches.
a) Do what you said. i.e. have a script tag which has two chained promises inside, each of which creates a new script tag, appends it to the DOM, adds an onload event function which would be the promise's resolve function and lastly sets its src attribute to the resource's URL. When the script from the first promise loads, the second promise should execute and do the same thing.
b) Take the middle road. Have the vendor file in the head, to load synchronously, and have the application file at the very bottom of the document, to load after everything else finished.
In my opinion the first option is an overkill.
EDIT: Example for a)
<script>
var p = new Promise(function(resolve, reject) {
var scriptTag = document.createElement('script');
document.head.appendChild(scriptTag);
scriptTag.onload = resolve;
scriptTag.src = 'URL_to_vendor_file';
});
p.then(function() {
var scriptTag = document.createElement('script');
document.head.appendChild(scriptTag);
scriptTag.src = 'URL_to_application_file';
};
</script>
Note: The example above can be written and without the use of promises

Should I use defer on script which are already at just before the bottom body tag?

This question has always bothered me every time I put my js files at the bottom of the page. if I put all js files at the bottom before the closing body tag then I think that the browser will first download all the html and style sheets then it will parse the html and css and at last it will send requests for js files. So,
Would using defer on js files which are already at the bottom make any difference?
Are non deferred scripts at the end just before body tag render blocking?
Another question I have is if I put all js file in the head and use defer on them. Would this be equivalent to placing all js files at the bottom? Would seeing js with defer in head the browser make request to the server and then continue downloading rest of html file or will it make request to server only after downloading all html and css?
As far as I know async is equivalent to defer and the only difference is the js will be executed when downloaded without respecting the order of files. So,
Would using async on js files which are already at the bottom make any difference except from the order in which they are executed?
Looking through the HTML 5.2 spec for Scripting, one finds this illustration W3C uses.
What we see here is that using defer fetches the script while the HTML is being parsed, but waits until parsing is concluded before executing.
async, on the other hand, fetches alongside parsing, and once the fetch is complete, HTML rendering is paused to execute the script.
Since HTML execution is synchronous, one can assume that using defer on scripts placed just before </head> would be almost like placing them just before </body>.
However, as Chris Moschini states, I would not trust defer. I feel this StackOverflow answer as a whole would better explain how defer affects loading JavaScripts.
The defer attribute is a boolean attribute.
When present, it specifies that the script is executed when the page has finished parsing.
Note: The defer attribute is only for external scripts (should only be used if the src attribute is present).
This post I found explains it well: https://flaviocopes.com/javascript-async-defer/
Ideally, the best practice is to have <script defer... in . If you use a CDN, for example, this allows the script to be downloaded while the HTML is being parsed.

errors prevent embedded javascript from running

I have a service where users embed a javascript code in they website, in the body tag. Sometimes the page where the code is embedded throws a javascript error from other javascript files which prevent our script from running.
Is there a way to design our code so it doesn't interfere with other javascript scope.
The only solution I can think of is to put the js code in an iframe.
The best way to make sure that your code always runs, is to make sure it is always loaded first.
As long as no scripts are dynamically loaded or marked as async or defer, scripts are run or evaluated in the order encountered in the page. So, the first scripts encountered run first.
In other words, by default, script tags are downloaded and evaluated sequentially as they are encountered in an HTML document.
An externally referenced script file that must be loaded will cause all further javascript execution to wait until that externally referenced file is loaded and parsed and runs.
What all of this means is that you should make sure your script is at the very top of the HTML that is being loaded, meaning it will be processed first and other scripts will not have a chance to interfere with yours.
reference: http://docstore.mik.ua/orelly/webprog/jscript/ch12_03.htm

Gateway Timeouts and Browser Rendering

If my browser makes a GET to a script src which is currently having a gateway timeout aka 504, why does the browser hang and stop rendering until the response is actually delivered 60 seconds later? Aside from crashing the browser, isn't this the worst thing that could happen to a production javascript application? Is there anything you can do as the app dev to prevent this from blocking the rest of the rendering and script execution?
If the script is inline (e.g. not dynamically loaded) and not marked defer or async, then the script must be processed synchronously in order and the browser cannot proceed without it. Inline <script> tags (without any special attributes) are processed in order as encountered and the browser MUST process them that way.
If you want your page to render without waiting for the script to load, then you can either load it dynamically or you can mark it async or put the <script> tag right before the </body> tag and the page rendering will not wait for it. If using defer or async, you must make sure that no other scripts are dependent upon the loading of this script, otherwise they might run before this one loads.
See these references for more info:
load and execute order of scripts
Script Tag - async & defer
If you are talking about javascript in the DOM within script tags, browsers will always load them synchronously which is why it is important to have the bulk of your JS at the bottom of the page. If this becomes a big issue I would recommend using using an async loading library such as lab.js http://labjs.com/.
If you are getting into more advanced JS and want to utilize something like the AMD pattern for script loading and dependencies you can use http://requirejs.org/.

Javascript script/dom dependency?

When helping someone with a website that is rather large and have many includes I hit a bug and couldn't understand it. It was something like this
<script src=...></script>
<div ...
<script>
alert('myscript');
</script>
This page worked fine until I use that section of html and used jquery to ajax the content in. It broke the code but I don't understand why. I seen my alert. I can see the script is being access via the browser network log. I see some of the results of the first script tag but its broken.
Why does order matter? I thought as long as the dom is ready and the script is executed everything should be fine. But in this case being ajaxed in breaks it. I couldn't spend much time but it was curious to see something was dependent on timing.
--edit--
Also I notice if the script is already included on the page ajaxing in the content it will run fine
Does anyone have any idea why ajaxing in content breaks? When its not ajaxed in its fine.
Based on what you say, I give the following assessment :
40% likely -- it is about script load. Dependencies within the ajaxed script to other scripts, variables you define on the page, or even DOM content that is supposedly loaded could be not loaded at the time the script is ajaxed and executed.
Try changing the order of the script tag on the page, putting the loading of the script inside a document ready event handler, or delaying the script execution with setTimeout or defer="defer" -- or if you are really cool create a boot loader that ensures every script is loaded and executed in the exact order you specify : by chaining sets of dependency free simultaneous loads, to sequences of dependent loads.
Script1 <---- depends on --- (Script 2.1, Script 2.2, Script 2.3 )
<--- depends on --- Script3.
So load 1 first, then all the 2. scripts, then 3.
40% likely -- it is about security model. The website where you are ajaxing it from, Where is that? What is its relation to the domain the page is on? Are you testing this on localhost ?If so there are more restrictions. What about on an actual server? Is the Access-Control-Allow-Origin header set appropriately on the ajax response?
20% likely -- it is a circular dependency between the script and the DOM. Say some event handler on element X closes on a scope that references element X. Then there will be a reference to X inside a reference to X so they can't both be garbage collected, so X will persist, cause a memory leak, and possibly create an unusable reference which could be breaking your code.
--edit--
Based on your comment about .html(...) I think .html or .load to run scripts is too messy, and may not even work at all. See .load() doesn't load scripts for a nice way to load scripts with ajax. Or you could jQuery.getScript(...).
Also I seem to remember having issues even with loading html nodes from plain HTML using ajax. It just seems too messy to me. If you want to transfer structured information across ajax, use JSON, then present that information on your side with javascript and HTML. So, don't grab the whole data + presentation, just grab the data, then do your own presentation on your side. It's much neater.

Categories