Javascript onload and script callback functions, which takes the precedence?
Asked Answered
F

3

9

I'm loading an external script that uses callback function, which returns some specific data. If this data is not received error should be displayed.

Here is the code I've made:

<script>
//setting initial state so that function will only work once
var visitors_loaded=false;  
var my_callback = function( data ) {
    if (visitors_loaded) return 0;
    if (data) { 
        //success: callback function is called and it has a proper data
    visitors_loaded=true;
    alert(JSON.stringify(data));
    }
    else alert ('error'); //something went wrong
};
</script>
<script onload="my_callback(null)" onerror="my_callback(null)"
src="https://api.clicky.com/api/stats/4?site_id=32020&sitekey=9a19b1a4d1171193&type=visitors&date=this-month&output=json&json_callback=my_callback"></script>

As you can see... many things that can go wrong with the script, so I naturally added an onerror event. This on error event actually fires if you change host name or domain of the script to something non-existent.

However, if you only make changes to the url of the script, it can still connects to the server and fires an onload event instead. My callback function will not be called for those invalid requests, so I added an onload handler as well.

Now the problem is, if all loaded normally and data was returned, it will fire both, callback function and onload. I have noticed that callback function is triggered before the onload and set the visitors_loaded variable so that the handler function is only called once.

So far it works perfectly in JS fiddle and my offline site but I wonder if this is an expected behavior? Will that json_callback function always have precedence before the onload handler?

https://jsfiddle.net/5sfk9ht5/4/

Frannie answered 11/6, 2016 at 9:21 Comment(0)
B
3

Will that json_callback function always have precedence before the onload handler?

If the external script calls my_callback synchronously then yes.

The scripting section in the official html5 specification describes how these things are supposed to work. The specification is quite general and has to deal with a lot of details conserning encoding, CORS, ignore-destructive-writes counter and so on. But for this question we don't care about these specifics.

In step 4 there is a note:

Note: This is where the script is compiled and actually executed.

And in step 7 the load event is fired:

fire a simple event named load at the script element.

So the specification defines that the load event is always fired after the script has been executed.


As you see the specification also tells us why the onerror event is not fired if you change the URL. The error event is only created if loading the script fails. But all requests to https://api.clicky.com/api/stats/ return a HTTP 200 status. The invalid URLs return XML and thus a SyntaxError is thrown. But this does not cause the onerror handler to be triggered.


As others have mentioned if the callback is called asynchronously they can call your callback after the onload event. But I don't see a reason why they would do this async in your external script.

Bedspread answered 20/6, 2016 at 13:16 Comment(1)
Nice mentioning the spec!Maples
S
4

onload in older IE might not work for you 'onload' handler for 'script' tag in internet explorer, if you want to run all browsers you might need something like this https://jsfiddle.net/e287523t/2/ and should work for all

      function addScript(fileSrc, callback) {
        var head = document.getElementsByTagName('head')[0];
        var script = document.createElement('script');
        script.type = 'text/javascript';
        script.onreadystatechange = function() {
          if (this.readyState == 'complete') {
            callback();
          }
        } 
        script.onload = callback;
        script.src = fileSrc;
        head.appendChild(script);
     }

Then the rest is defining my_callback and calling addScript

        my_callback = function(someData) {
          alert(JSON.stringify(someData));
        };
Scissile answered 15/6, 2016 at 2:28 Comment(0)
M
3

Now the problem is, if all loaded normally and data was returned, it will fire both, callback function and onload. I have noticed that callback function is triggered before the onload and set the visitors_loaded variable so that the handler function is only called once.

This is because the callback is launched from within the called script from api.clicky.com

So far it works perfectly in JS fiddle and my offline site but I wonder if this is an expected behavior?

I see what you are getting at, a related question about what happens when a script fails is here, but I did some tests for you and here are the results.

tester.html:

<script>

var onLoadTest = function() {
    console.log("Onload Called!");
};


var callbacktest = function() {
    console.log("Called from other script!");
};

var errortest = function() {
    console.log("Callback OnError!");
};

</script>

 <script onload="onLoadTest()" onerror="errortest()"
 src="script.js"></script>

script.js:

function otherScriptFunc()
{    
    //call the function in the original script
    callbacktest()
}

otherScriptFunc(); // first call to other script
setTimeout(otherScriptFunc, 0); // final call to other script

Results from the console log

Called from other script!
Onload Called!
Called from other script!
  1. Your OnLoad will be called when the JS in the other place has finished being parsed (async functions will do their own thing). For example, otherScriptFunc(); will call before onload but setTimeout(otherScriptFunc, 0); will be called after onload

  2. Your OnError will only be called if there is a GET request error. IE, the file cannot be found, or URL cannot be resolved - nothing about what is in the file. (I tested it separately, just mess with the file name)

  3. Your callback passed to the other script could be called whenever the other script feels like it. It has a reference to it and could decide to hold onto it for a little while and call it later after it has played around. Which means it could be in an async call waiting for data elsewhere. Which means, theoretically, your onload could in fact be called before the callback, but it depends on the other script and there is not a lot you can do about it.

Will that json_callback function always have precedence before the onload handler?

It's not about precedence, it is just dependent upon when the other script decides to call it.

Maples answered 15/6, 2016 at 2:12 Comment(0)
B
3

Will that json_callback function always have precedence before the onload handler?

If the external script calls my_callback synchronously then yes.

The scripting section in the official html5 specification describes how these things are supposed to work. The specification is quite general and has to deal with a lot of details conserning encoding, CORS, ignore-destructive-writes counter and so on. But for this question we don't care about these specifics.

In step 4 there is a note:

Note: This is where the script is compiled and actually executed.

And in step 7 the load event is fired:

fire a simple event named load at the script element.

So the specification defines that the load event is always fired after the script has been executed.


As you see the specification also tells us why the onerror event is not fired if you change the URL. The error event is only created if loading the script fails. But all requests to https://api.clicky.com/api/stats/ return a HTTP 200 status. The invalid URLs return XML and thus a SyntaxError is thrown. But this does not cause the onerror handler to be triggered.


As others have mentioned if the callback is called asynchronously they can call your callback after the onload event. But I don't see a reason why they would do this async in your external script.

Bedspread answered 20/6, 2016 at 13:16 Comment(1)
Nice mentioning the spec!Maples

© 2022 - 2024 — McMap. All rights reserved.