JavaScript Can Have An Interesting Interpretation of Order

There is an interesting little quirk with the way in which JavaScript decides which function it should execute next. You see, while the JavaScript engine has a single thread of execution, it creates the illusion of multiple simultaneous processes running at once by utilizing a queue of functions to execute. This means that every time you make a call to a function in your JavaScript, there is no absolute guarantee that it will be the next piece of code run, as there may have been other events triggered that beat your custom function onto the execution queue.

You may be thinking that this is interesting and all, but what does it matter to me? Well, lets take the following snippet of code as an example.

var func1 = function() {
    func2();
    $(form).submit();
},
func2 = function() {
    var iframe = $('<iframe src="blank.html" class="hidden" id="testiframe"></iframe>');
    $("div:last").after(iframe);
    $("#testiframe").on("load", onIframeLoad);
};

So, based upon looking at the code above that utilizes some jQuery to make things a bit more straightforward, does the function onIframeLoad get run first or does the form get submitted to the server first? Does the function onIframeLoad ever get called?

As is the case with many things in the world of JavaScript and Web Development, the answer is that it depends. Lets address the second question first. We cannot be absolutely certain that onIframeLoad will ever be called because we are not certain that the blank.html file will load after we are able to attache the event handler to the newly created iframe. It is possible that there is so much else going on with the JavaScript on the page that blank.html will load before we setup the event handler. However unlikely, this is a definite possibility.

As for the first question, it again comes down to a question of timing. Without more knowledge about what exactly is going on with all the other JavaScript on the page and what ever plugins are running in the browser. In general, I would expect onIframeLoad to be executed first, but I would not want to base the functioning of my website on that expectation. If you wanted to guarantee that onIframeLoad is run and is run before the form is submitted, I would change the above code to something similar to the snippet below, which forces the order to be respected instead of guessing at the order.

var func1 = function() {
    func2();
},
func2 = function() {
    $("document.body").on("load", "#testiframe", onIframeLoad);
    var iframe = $('<iframe src="blank.html" class="hidden" id="testiframe"></iframe>');
    $("div:last").after(iframe);
},
onIframeLoad = function() {
    $(form).submit();
};

Related Posts

Jul 15, 2014
2 minutes

The Easiest Way to Create A Solution That Works

The easiest way to create a solution that works…is to do it right the first time. Yes, this is a bit of a cop-out, but it turns out to be an important factor to keep in mind when you are tempted to come up with a quick and dirty solution for a problem that does not follow established best practices and is likely to have code quality issues later.

I have run across many sections of code that I or other developers have written in the past that we thought were “good enough” at the time it was written, yet, I was revisiting the code because we discovered a bug in it. Many times, this code had an issue that would have been trivial to fix at the time it was written, if it were only found. It seems that as a developer, we tend to find the least sufficient solution that will solve the immediate problem we are experiencing instead of finding an optimal solution that will be easily maintained months and years after it was written.

May 23, 2014
2 minutes

Avoid SiteCatalyst's useForcedLinkTracking and target="_blank"

All sites rely upon some third party analytics software to track at the very least the number of visitors to a site. Many sites use Google Analytics, which provide much more information that just the number of visitors. Another option that some of the bigger sites use is Adobe Analytics, aka SiteCatalyst to enable more custom tracking options that are not evident through the Google Analytics interface.

One feature of SiteCatalyst is that it allows you to set an option useForcedLinkTracking that will track every link on your site for clicks whether or not you have setup custom tracking for the links or not. Effectively what the code does is create a JavaScript event handler to intercept all click events on the <a href="http://url.com">Link</a> hyperlinks. Once they are intercepted, SiteCatalyst sends its tracking information to its servers and then procedes to attempt to make sure that the link functions properly. Unfortunately, in some versions of the SiteCatalyst code, it attempts to create a synthetic click event that works in many cases. However, if you are using Safari with the popup blocker turned on, and a target="_blank" in the hyperlink, then it will trigger the popup blocker, which simply ignores the click, and the user sees nothing happen at all. In order to fix it, hopefully the latest version of the SiteCatalyst code will handle it, turn off useForcedLinkTracking, or, as the very last resort, convert the <a /> links to another type of element and use JavaScript to open the new window manually when listening for the click event on the new element. It seems this works all the time, but it will prevent SiteCatalyst from tracking those clicks.

Jun 2, 2014
2 minutes

Defensive Development - Fail Fast or Go Home

Defensive Development is a programming practice that is frequently misunderstood, but is nevertheless a critical practice to follow when working in many environments. I have seen articles written that argue that defensive development simply causes nonsensical null checks to be written, and as a result of seeing people writing bad code defensively, argues that no one should practice defensive development. There are other articles that, like many things in software development, argue that you should always use defensive development for everything.