Loading external JavaScript is like waiting until runtime to compile an external dependency. A lot can go wrong. It’s difficult to escape the need to load external JavaScript on many of today’s web applications. Many of our sites need to compose functionality from social networks, transaction processors, analytics, and advertising networks with our own content. It’s everywhere.

Let’s consider an example, say you want to use a third-party payment processor so you can take a credit card. They ask you to include their script and then you make calls into their functions. Maybe something like this:

<script src="https://cdn.cashmoney.com/cashmoney.js"></script>
<script>
  cashmoney.setMyKey('AwesomeApp');

  var $form = $('#checkout-form');
  $form.on('submit', function() {
    $form.token = cashmoney.card.getToken();
  });
</script>

Simple enough right? A quick copy-paste and we’re making some big money with our site. So what’s the problem? Well, what happens if cashmoney.js isn’t available?

ReferenceError: cashmoney is not defined.

How is this possible?! Are people messing with us? Not only does this error break the token capturing, but the script execution stops on the first line, the call to cashmoney.setMyKey, and the submit event is never attached. This could have all sorts of potential issues for the behavior and security of the page, but it can also cause some really terrible user experiences.

We’re loading cashmoney.js from an external server, and a lot can go wrong between a client and a server. Many of your visitors will come to you on mobile browsers over “less-than-ideal” network connections. Mobile networks are treacherous. So much can happen between the browser initially loading your page and making the first DNS request to cdn.cashmoney.com or starting an SSL handshake, like entering a tunnel. For whatever the reason, their network worked great when the browser started building the page, but failed when trying to load the resource from CashMoney. If their resource doesn’t load, then cashmoney never gets defined and you’re left in a pickle.

While this isn’t common, we at TrackJS see evidence of this happening across most websites with large mobile audiences. It’s probably affected some of your users. So what can we do about it?

<script src="https://cdn.cashmoney.com/cashmoney.js"></script>
<script>
  // Make sure that cashmoney loaded successfully before we blindly reference it.
  if (!window.cashmoney) {
    // Show User UI that the order form is temporarily unavailable
    // Probably log this so we know that it happened
    trackJs.track('cashmoney failed to load for a visitor');
    return;
  }

  cashmoney.setMyKey('AwesomeApp');
  ...
</script>

Simple checks like this totally solve this class of problems. Simply make sure the JavaScript API has loaded before using it. Now, you have the opportunity to intervene and present a much better user experience for customers when something goes wrong.

Anytime you introduce an external domain, such as a third-party service or CDN, this problem can manifest itself. Better safe than sorry. Have a look at your codebase and make sure you’re safety-checking for any external scripts you may be loading.

This is one of the reasons why we make the TrackJS library available on NPM. By referencing the script and including it at build-time, you can rest assured that it will be delivered with the rest of your web application.

As you well know, a lot can go wrong running a web application. Loading errors are only one example. You’ll need solid tools to help you understand when problems happen, and how to fix them fast. If you need help, checkout TrackJS with a free 30 day trial. I promise, it can help make your app even more awesome.