Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When does onload fire for async script?

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>
like image 322
sgu Avatar asked Oct 31 '25 03:10

sgu


2 Answers

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>
like image 185
Kaiido Avatar answered Nov 01 '25 17:11

Kaiido


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()">
like image 34
Maik Lowrey Avatar answered Nov 01 '25 19:11

Maik Lowrey



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!