JavaScript

Improving your JavaScript Performance

Computers are getting faster. Mobile devices are catching up too. Browsing the web on your phone no longer needs to be an inferior experience. But despite all this advancement in technology JavaScript is still slow. Faster then before but still slow.

Well, it depends on your code mostly. There are many website that I never open in my old Android 2.3 phone. If I do, the browser hangs, then the phone hangs, then in some cases my whole phone crashes and restarts. Is it because my phone is old? I would say yes if it was the same case for every website. But there are only a few select culprits. No I am not talking about running games or heavy applications. A good example is qz.com. It just crashes my old phone.

What is the problem really? Do you have to have no JavaScript to run these websites? No. The problem is always the code, and I will show you how you can make sure your code doesn't crash your users machine.

Loops - The biggest culprit

No, you don't have to delete all your for loops. What matters is what happens inside your loop. You can write some code that performs well if it is only called once at a time, but inside a loop it slows down the machine.

Example:

$(".results").click(function() {
    var value = $(this).html();
    $(".display").eq(0).val(value);
});

This code is not optimized but it only runs once at a time. So if it takes 200 milliseconds to run we don't care. After the 200ms the browser has nothing else to do. But if the code was supposed to run inside a loop, it will be a different story:

$(".results").each(function(i) {
    var value = $(this).html();
    $(".display").eq(i).val(value);
});

There are some problems here. First, this will run fast on your desktop machine. Developers mostly work on more than capable machines. So they won't see that running something like this on a phone can drastically slow things down. Second, we are writing redundant code here. For every result there is a loop that traverse the DOM multiple times. Remember that touching the DOM is expensive in JavaScript.

This is one of the reasons I don't suggest people start learning JavaScript with jQuery. It abstracts the problem and most people don't worry about what is happening in the background. But don't worry, this is very easy to improve.

var display =  $(".display");
$(".results").each(function(i) {
    var value = this.innerHTML;
    display.eq(i).val(value);
});

Here I made one major change. I moved the selector outside of the loop. This means, the DOM is not traversed inside the loop. I reused the variable display instead of recreating it after each iteration.

On scroll

The new trend is to have some animations triggered based on how far down you scroll. If this is not implemented correctly your website becomes unusable. For example, you want to have a menu stick to the top of the window after the user scroll past it. Sure it looks cool, but make sure you test it on smaller devices to see if they work as intended.

The problem is when you scroll, the browser can trigger the event for almost every single pixel it scrolls. If you scroll down 200 px, you might call your function 200 times. If your function is also checking for values in the DOM then you are accessing it just as much. Again, it may pass on your laptop or desktop, but it will choke your Smartphone.

Example:

window.onscroll = function() {
    var animatedDiv = document.getElementById("fading-div");
    var divPosition = getDivTopPositionPixel(animatedDiv);
    var currentPosition = window.pageYOffset;
    if (currentPosition >= divPosition){
        fadeIn(animatedDiv);
    }
};

This very few lines of code can freeze your browser. Depending on your browser and OS, this code can be called hundreds of times while you scroll. And the good news is that you can improve it. I will give you a simple solution that is by no means the best but it can help.

First of all, we don't have to check the values on the DOM element every time we scroll, we can save them in a variable once which is already an improvement. The big feat however is to minimize the work done during the scroll.

var animatedDiv = document.getElementById("fading-div");
var divPosition = getDivTopPositionPixel(animatedDiv);
var isScrolled = false; // is the browser scrolling?
var frequency = 100; // Milliseconds

window.onscroll = function(){
    isScrolled = true;
};

var scrollTimer = setInterval(function() {
    if (isScrolled) {
        isScrolled = false;
        var currentPosition = window.pageYOffset;
        if (currentPosition >= divPosition){
            clearInterval(scrollTimer);
            fadeIn(animatedDiv);
        }
    }
},frequency);

I added a few more lines of code. What's notable here are the variables isScrolled and frequency. We set isScrolled to true when the page is scrolled, even if it is one pixel. Nothing happens right away. At least not until the scrollTimer interval fires. I set mine to 100 milliseconds (frequency) but you can set it to a lower value. When that function fires, it checks if the page has been scrolled (isScrolled) Then tries to do the animation. Otherwise nothing happens.

The advantage here is if the user is scrolling all the way to the bottom of the page, our code will only run a maximum of 10 times, and even then it will do very little work unless the animation is triggered.


There are other places where you can run into other performance issues. Your goal is to make sure that you are not running processor heavy code at short time intervals. Another popular place where the performance improvement we did above can be useful is if you are using the mousemove event. There is almost never a reason to run code at every pixel movement.

I hope you learned something from this tutorial. If you have questions or comments feel free to ask in the comments form below.

Until next time.

Originally Posted on Feb 9, 2015 @ 00:24


Comments

There are no comments added yet.

Let's hear your thoughts

For my eyes only