Attempting to detect a slow network connection in JavaScript

About a 7 minute read

Written by on

#javascript #network

I was working on my anime site the other day and had a thought.

The random anime of the day loads this big image. It’s not really essential to the home page…so if the user’s network is slow, maybe I should just not make that request?

Oh boy did that ever open up a can of worms.

Using a Timeout

This is what my mind immediately jumped to. Set some sort of timeout at the beginning of the page, then have a page load listener that will clear the timeout when the document finishes loading. If the timeout ever fires, then you know that the connection is slow.

<head>
    <!-- Other head element stuff -->
    <script>
        // In the head so it executes ASAP
        var slowpoke = setTimeout(function() {
            // Do something cause it's slow!
        }, 500);
        window.addEventListener('load', function() {
            clearTimeout(slowpoke);
        }, false);
    </script>
</head>

This solution has a couple of nuisances with it.

Timeout Timer

You have to manually set the amount of time before the timeout fires. This isn’t really ideal, since it could vary from site to site. It takes extra time and isn’t exactly perfect. You pretty much have to make a judgement call on when you want to make the cut.

Listening for Load

Oh, whenever the page loads, clear the timeout. That doesn’t seem so bad, right? Well, what if I wanted to prevent something from loading? That’s a very plausible use case.

For example, I don’t want to make the random anime of the day call. That call happens on load. So, when the load event fires, that call is already being made.

Again, with a little more work, we could adjust the code to wait for the load event to fire before doing anything else. After all, the stuff that is cut from a slow connection is deemed expendable to a certain extent, right?

But…then we are delaying a request for users that have adequate connection. Even if it is a short time, a delay is still a delay.

Network Information API

YES! Now we’re talkin’.

This is exactly what I need for my project. This API allows you to detect multiple things about the users network. Want to know if the user is on bluetooth or cellular? You can do that. Want to know if the connection is 2g or 3g? You can do that.

This is GREAT!….

…but the browser support is shit.

Browser Support

Can I Use netinfo? Data on support for the netinfo feature across the major browsers from caniuse.com.

As you can see, you are pretty much looking at Chrome and Opera. The mobile support for this api, which is where I feel the real benefit would lie, is pretty spotty. On Android it’s pretty good, but not so much for iOS.

Progressive Enhancement

Whatever! We can still use it if we want! We just have to make sure it doesn’t break anything if it’s not supported.

var connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;

Alright. So the first thing we have to do is store the connection in a variable. Then, we get to figure out the logic. We want the code inside to execute if the network api is not supported, or it is and not slow.

var connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
if(!connection) {
    // Network API not supported
    // Do stuff and things
}

That was simple. We just put the reverse operator on the connection variable, since if it is unsupported it will return undefined. So now, if the api isn’t supported, the code within will execute.

var connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
if(!connection || (connection.effectiveType !== "slow-2g" && connection.effectiveType !== "2g")) {
    // Network API not supported
    // or supported and not 2g
    // Do stuff and things
}

TADA! If the network api is supported, then we check to make sure that its effectiveType property does not equal “slow-2g” or “2g”.

So why not equals to, instead of equals to? We could’ve checked the effectiveType to make sure it was “3g” or “4g”. Well, since this is still experimental (draft status), I wanted some extra protection. We make sure that if it’s not supported the code executes, but I also want to make sure it executes just in case these values change.

So if we did a hard check for “3g” and “4g” and down the road they changed those values to “fast” and “very fast”, the condition would be falsey. If we do not equals to and they change the values, it’ll be truthy. For example, if “slow-2g” and “2g” changed to “super slow” and “slow”, the code would just always be truthy, same as if the api wasn’t supported.

I’d rather the code always run, than never run. At least for this use case.

You can check out more info on the Mozilla developer page, or the official spec.

Conclusion

As it turns out, detecting a slow connection is actually pretty complex. I’m sure there is some mastermind out there that has come up with a super cool way to do a quick check, but for us regular folks (or just me), it’s a pain.

As for me, I’m thinking that I may just implement some network api stuff lightly. My website load time is good, so prioritizing assets is icing on the cake. If the browser supports this newer technology, great; otherwise, it’s no biggie.

Besides, it’s only a single variable and conditional statement. Super simple and easy.

Thanks for listening to my nonsense!