2

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:

  1. What is the meaning of using both async and defer in this context?
  2. Why did Google choose to use this technique? Does it have any performance or other benefits?
  3. In the onload event, why do they first assign an empty function ( function(){}; ) to the event before calling handleClientLoad()?
  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?

Thanks.

1 Answer 1

6

This is fairly well-covered by the WHAT-WG living standard for HTML's section on async and defer, which includes this handy graphic:

enter image description here

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:

  1. 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();
        }
    }
    
  2. Have mainScriptLoad in your separate file.

  3. 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.
Sign up to request clarification or add additional context in comments.

3 Comments

Last question - why both onload and onreadystatechange are needed? For supporting different browsers?
@danielv: Yes. script tags didn't used to raise the load event, back in the mists of time, but did raise the onreadystatechanged event.
@danielv: Thanks! Fixed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.