Javascript async load with jquery append() function inside - javascript

Edit: I am looking for a way to async "include" a javascript file inside another.
What if I load a javascript file like this:
<script src="http://my.website.com/file.js" async="" type="text/javascript"></script>
Inside the javascript file I have
$('head').append('<script src="http://other-website.com/other-file.js" type="text/javascript"></script>');
Will this file still be loaded async including the other-file.js?
I am guessing that I need to append it with async like that
$('head').append('<script async="" src="http://other-website.com/other-file.js" type="text/javascript"></script>');
To completely load all javascript async, right?
But inside other-file.js there are functions which I am using inside file.js

Yes you would need to add the async attribute, and if you depend on that other file, you'll need some complex logic to know when it gets loaded.
There are libraries built for this exact purpose, have you looked into them? I could recommend RequireJS, this way you can wrap your code like this:
require(["helper/util"], function(util) {
//This function is called when scripts/helper/util.js is loaded.
//If util.js calls define(), then this function is not fired until
//util's dependencies have loaded, and the util argument will hold
//the module value for "helper/util".
});

It depends on where the JS is running that has the .append() line in it, and whether it has the async attribute.
If it is running in the head of your document, and it is appending to head, then it will not be asynchronous (will block) if the appended <script> tag doesn't have the async attribute.
The reason is that file.js will very likely load and be parsed before the <head> of the document is done being processed. JavaScript will block the browser's HTTP connection until it's done parsing any external JS without async, which means and it will add the new <script> tag below it in the <head> and then proceed to process it and block the HTTP connection, unless the async attribute is present.

Related

Script async/defer/onload usage in Google's API javascript samples

In various javascript samples which Google provides for its API (e.g here), they use the following code to load the script from the html:
<script async defer src="https://apis.google.com/js/api.js"
onload="this.onload=function(){};handleClientLoad()"
onreadystatechange="if (this.readyState === 'complete') this.onload()">
</script>
My understanding is that async/defer tell the browser when to load and execute the script and somewhat contradict each other. I have few questions:
What is the meaning of using both async and defer in this
context?
Why did Google choose to use this technique? Does it have any
performance or other benefits?
In the onload event, why do they first assign an empty function ( function(){}; ) to the event
before calling handleClientLoad()?
If I want to move the entire javascript to a separate js file,
what's the best approach to load both scripts? Since the new js file
will depend on api.js and can't be loaded asynchronously?
Thanks.
This is fairly well-covered by the WHAT-WG living standard for HTML's section on async and defer, which includes this handy graphic:
1. What is the meaning of using both async and defer in this context?
If the browser supports async, it ignores defer and does the async work. If not but it supports defer, it does the defer instead. If it doesn't support either, the script blocks DOM parsing, but all modern browsers support at least one.
2.Why did Google choose to use this technique? Does it have any performance or other benefits?
async fetches the script without blocking DOM parsing and rendering, and runs it as soon as it's available even if DOM parsing and rendering is still underway. defer will also avoid blocking DOM parsing and rendering, but won't run the script until parsing is complete (e.g., potentially later).
3. In the onload event, why do they first assign an empty function ( function(){}; ) to the event before calling handleClientLoad()?
This becomes clear if you look at onreadystatechanged: Basically it ensures that handleClientLoad is only called once by GAPI, not potentially twice (once by onload and once by onreadystatechanged.)
4. If I want to move the entire javascript to a separate js file, what's the best approach to load both scripts? Since the new js file will depend on api.js and can't be loaded asynchronously?
Well, it can be loaded asynchronously, you just have to handle the race condition with api.js. I'd probably:
Have handleClientLoad in an inline script above the script tag loading api.js, something like this:
var clientLoaded = false;
function handleClientLoad() {
if (!clientLoaded &&
typeof mainScriptLoad !== "undefined" &&
typeof gapi !== "undefined") {
clientLoaded = true;
mainScriptLoad();
}
}
Have mainScriptLoad in your separate file.
At the end of your separate file, call handleClientLoad.
That way:
If your script runs first, it'll call handleClientLoad but handleClientLoad will see that the GAPI isn't loaded yet and won't do anything; later, when the GAPI loads, it will call handleClientLoad and that will call mainScriptLoad because everything is ready.
If your script runs after GAPI loads, it'll call handleClientLoad but handleClientLoad will see that your main script isn't loaded yet and not try to call it. Later, when your script loads and calls handleClientLoad, handleClientLoad will call mainScriptLoad because everything is ready.

Run external javascript file on load

We made a website through webnode.nl, because we hadn't enough time to make a website using html. Now we added a widget using a external site using a script tag with the link to this site. But through this widget the page is loading slow. Now I had the idea to run the script after the page is loaded. But I can't access the code of the widget and I can't access the html of the website. I can only access the code block in which I pasted the script tag.
The script tag:
<script type="text/javascript" src="http://mycountdown.org/countdown.php?cp2_Hex=d21a1a&cp1_Hex=F9F9FF&img=-3&hbg=&fwdt=420&lab=1&ocd=My Countdown&text1=Valentijnsdag!&text2=valentijnsdag!&group=My Countdown&countdown=My Countdown&widget_number=3015&event_time=1455408000&timezone=Europe/Amsterdam"></script>
Can someone help me?
PS: English is not my first language, so I don't know if my English is correct
Place it at the end of the <body> and add async to the script tag i.e.
<script async src=""></script>
More info here: http://www.growingwiththeweb.com/2014/02/async-vs-defer-attributes.html There is also the defer attribute.
Typically you want to use async where possible, then defer then no
attribute. Here are some general rules to follow: If the script is
modular and does not rely on any scripts then use async. If the script
relies upon or is relied upon by another script then use defer. If the
script is small and is relied upon by an async script then use an
inline script with no attributes placed above the async scripts.
Edit
You may be better using Defer:
defer downloads the file during HTML parsing and will only execute it
after the parser has completed. defer scripts are also guarenteed to
execute in the order that they appear in the document.
if you can write script blocks then write the following in whatever you are allowed to use.
<script>
// Create a <script ...></script> element
var widget = document.createElement('script');
// Set src="URL_of_widget"
widget.setAttribute('src', 'http://mycountdown.org/countdown.php?cp2_Hex=d21a1a&cp1_Hex=F9F9FF&img=-3&hbg=&fwdt=420&lab=1&ocd=My Countdown&text1=Valentijnsdag!&text2=valentijnsdag!&group=My Countdown&countdown=My Countdown&widget_number=3015&event_time=1455408000&timezone=Europe/Amsterdam');
// Set async
widget.setAttribute('async', 'async');
// Insert <script> as the last element child of <body>
document.body.appendChild(widget);
</script>

Make sure my .JS file loads every time before others

I have a website where I don't have access to the source but I can manipulate it using Javascript. I have a file called main.js that has been included at the very end of the includes to which I have the access to and I would like to run my custom Javascript code in that file. I have a .JS file with a function called helloWorld() on my server that I would like to load before any $(document).ready() callback fires, because one of the $(document).ready() functions on my website page/pages uses this function.
Custom .JS file:
function helloWorld()
{
alert("Hello World");
}
main.js file on the server (Accessible):
//All the JS code that the website uses
..
// My custom javascript code that includes my custom .JS file
$.getScript("helloWorld.js", function()
{
// Use anything defined in the loaded script...
});
Now I would like the helloWorld() to be loaded whilst the page is loading and before any $(document).ready() functions fired. I understand that loading this .JS file while the page is loading will possibly slow down the page load. Is there a bullet-proof way of making sure that my custom javascript function will be loaded prior to any $(document).ready()'s? If there is any other way I can achieve this, please do let me know. Looking forward to your suggestions.
Looks like I found a solution for your problem. I wouldn't suggest it, but it's the only way you can load an external script from another one before the DOMContentLoaded event fires.
Solution
Since that your main.js script is in the <head> of your document, you can be sure that it will be loaded and executed before any following part of the DOM. Given this, you can use a synchronous XMLHttpRequest to load your script and execute it.
This kind of technique has some pros and cons:
Pros: you can load and execute any script before DOMContentLoaded, and also multiple scripts sequentially.
Cons: your document will be frozen until the requests are completed.
Not that bad, if your script isn't enormous it will not drastically impact the loading time. We can still do it.
Implementation
First of all, make sure that your custom.js script is served over a link which will always be reachable, so that your request will not fail. Also make sure that your main.js script hasn't got async or defer properties, so that it will always be executed in the <head>, before the DOMContentLoaded event.
<!-- NOT GOOD -->
<script src="main.js" defer></script>
<script src="main.js" async></script>
<!-- GOOD :) -->
<script src="main.js"></script>
Now that you're ready, in your main.js script you'll need to:
Create and initialize a synchronous XMLHttpRequest object, and send() a GET request to your content.js script.
Create a <script> element, and put the result of your request (which is stored in the .responseText property of the request object) inside it.
Append the script to the <head> to make it run before the DOM is loaded.
Plus, if you also want your script to be removed right after execution (so it will not be visible to the users), you can:
Remove the <script> from the document after it has ran its code. You'll need to listen for the onload event for this.
Also, if you want to make your code run completely anonymously, you can wrap it inside an anonymous function to prevent the access to it from the global scope.
Here's a quick example of what you'll need to do in your main.js file:
(function() {
// Create the request and the script
var xhr = new XMLHttpRequest(),
s = document.createElement('script');
// Send the request to retrieve custom.js
xhr.open('GET', 'path/to/custom.js', false);
xhr.send();
// Listen for onload, and remove the script after execution
s.addEventListener("load", function(e) {
s.parentElement.removeChild(s);
});
// Load the code inside the script and run it in the head
s.textContent = xhr.responseText;
document.head.appendChild(s);
})();
Now your custom.js script will (anonymously) run before DOMContentLoaded, mission complete!
As far as I can see, there are multiple ways of doing this, but the best way would be to use something like Require.js or CommonJS to resolve your dependencies, concat them, and and publish the resulting concatenated javascript file (or many if you can divide your app into multiple sections).
The not-so-great method would be to use the main script to load other scripts by adding script tags, this way you can ensure its there since its the one loading the other scripts.

Mixing html5 <script async> with non-async <script> tags

After doing some interesting reading on async, I couldn't find any information on what's supposed to happen if you first have a regular script tag, followed by one with async.
I tried a quick test and it seems to do what I would hope: if I put a non-async tag first, it seems to always load it before the later async attributed tag. Here's the code I'm testing with:
test.html:
<!doctype html>
<html>
<head><title>test</title></head>
<body>
<script src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
<script src="test.js" async></script>
</body>
</html>
test.js:
alert(window.jQuery);
In every case it seems that jQuery is loaded. Maybe I'm missing something in my tests. Is this correct? Can I put dependencies in non-async tags and then the dependents using async? Is it particularly beneficial to do this?
Are there any gotchas? What would happen if you had some asyncs and then a non-async? Would the async'd js load first?
Here the questions I can answer. I'm not 100% sure its a long time ago.
That first script is sync loaded. That means that it will wiat until that file is fully loaded and after that it proceeds to the next line.
Depends on when you need this file to be loaded. If it has to be loaded before the page is loaded, then you shouldn't use async for that file.
The asyncs will load simultaneously with the one non-async. If you have two non-asyncs at the end. That two non-asyncs will load sync. (DUH)
The async will load when it is on that line.
By it I mean the reader
Non-async script tags block processing of the page. The browser may look ahead and load test.js before jquery has been executed, but the browser can not process the script as it does not know what jquery does to the page (document.writeln, changing the window object..).
So, yes it will work.
Doing this will make loading the page a bit faster, as one of the two script can be loaded asynchronously. It will probably not match the startup time of an optimizing, asynchronous loader though.

Best practice for lazy loading in JavaScript

What's the best way to dynamically load HTML content and inject it in the page (when the HTML contains both <script src="..." /> tags and function calls to those scripts)?
Consider this approach (for simplicity, I will consider jQuery):
<script>
$.ajax({
url: 'http://...',
success: function(html) {
$("body").append(html);
}
});
</script>
Let's assume that the returned html contains something as such:
<script src="some_script.js"></script>
<script>
some_function(); // function defined in some_script.js
</script>
Since some_function() is defined in some_script.js it will be available only after some_script.js was loaded but (usually) it will be executed before some_script.js will be loaded (thus causing an error).
Obviously, there are some solutions to overcome this issue, but what is the best practice in this case? Should libraries such as RequireJS be used instead?
The example above is a result of the pattern I use: I have a component which I will load only when it's going to be used (at that point I make an Ajax call to retrieve both the HTML and the required scripts). Still, it can happen that many scripts are required and it's easier to write them as a set of tags in the HTML template rather than loading them through JavaScript (this is also preferred as the script URL may be generated inside the application so a plain JS script may not be aware of the absolute script URL).
Actually Safari and Internet Explorer (and most likely others) won't execute <script>'s that are injected through Ajax as a security measure.
What I can recommended is that when you need a library of considerable size (yet isn't required for actual use of your web application), is to rather load the .js-file containing the library into your document after which you can use all properties and methods defined in the library. Attach a callback listener to your script loader and execute all code in the callback, not in the external .js file itself.

Categories