The following snippet is taken from an example in Google API doc. The intriguing part of this snippet is that onload
event handler in the two <script async>
in <head>
are defined later in the <body>
. Does the onload
event in the async script only fire after the <body>
are parsed? Does any spec provide such guarantee? Or this code is only correct under the implied assumption that these two particular scripts in <head>
takes a long time to fetch and execute?
<!DOCTYPE html>
<html>
<head>
<script async defer src="https://apis.google.com/js/api.js" onload="gapiLoad()"></script>
<script async defer src="https://accounts.google.com/gsi/client" onload="gisInit()"></script>
</head>
<body>
<script>
function gapiLoad() {
// do something
}
function gisInit() {
// do something
}
// there are other stuffs...
</script>
</body>
</html>
Onload EventHandler Supports these HTML tags: <body>, <frame> (deprecated), <iframe>, <img>, <input type="image">, <link>, <script>, <style>, <track>, <svg>, <use>, <foreignObject>, <image>, <object>, <embed
. (Merci to @Kaiido for completing this list.)
If you want to be sure that your JS only runs when the DOM is loaded, you can load a handler function from the body tag.
Note You need to know when using onload with async that when scripts are loaded asynchronously, they delay the onload event. Often, asynchronously loaded scripts load other scripts.
function start() {
gapiLoad();
gisInit();
}
function gapiLoad() {
console.log(1)
// do something
}
function gisInit() {
console.log(2)
// do something
}
// there are other stuffs...
<head>
<script async defer src="https://apis.google.com/js/api.js" ></script>
<script async defer src="https://accounts.google.com/gsi/client"></script>
</head>
<body onload="start()">
No async
doesn't ensure the script will be executed after the document has been parsed. It will load the script in parallel and execute it as soon as possible, so if the fetching of the script finishes before the parser reaches the <script>
where your callbacks are being defined, that would be a problem indeed:
<script async defer src="https://apis.google.com/js/api.js" onload="gapiLoad()"></script>
<script async defer src="https://accounts.google.com/gsi/client" onload="gisInit()"></script>
<!-- This one is blocking for at least 3s -->
<script src="https://deelay.me/3000/https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
function gapiLoad() {
console.log("loaded");
}
function gisInit() {
console.log("init");
}
</script>
defer
does that, but if both defer
and async
are set, async
's behavior wins, so we have to ensure only defer
is set.
<script defer src="https://apis.google.com/js/api.js" onload="gapiLoad()"></script>
<script defer src="https://accounts.google.com/gsi/client" onload="gisInit()"></script>
<!-- this one is blocking for at least 3s -->
<script src="https://deelay.me/3000/https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
function gapiLoad() {
console.log("loaded");
}
function gisInit() {
console.log("init");
}
</script>