Simple Throttle Function

When you’re handling events like window resize, keystrokes, mouse movement, and scrolling you need to be careful how many times you call heavy-handed functions. For instance, if you’re leveraging JavaScript to create responsive UIs in legacy browsers you probably don’t want to run complicated DOM-altering handlers 10 times a second when far fewer runs would be sufficient. Enter throttling.

Throttling is a means by which we can limit the number of times a function can be called in a given period. For instance, we may have a method that should be called no more than 5 times per second.

function callback () {
    console.count("Throttled");
}

window.addEventListener("resize", throttle( callback, 200 ));

In the above, our throttle function takes a callback, and a rate limiter. It will fire the callback at most once every 200 milliseconds, or at most 5 times per second. So what does the actual implementation of the throttle function look like?

function throttle (callback, limit) {
    var wait = false;                 // Initially, we're not waiting
    return function () {              // We return a throttled function
        if (!wait) {                  // If we're not waiting
            callback.call();          // Execute users function
            wait = true;              // Prevent future invocations
            setTimeout(function () {  // After a period of time
                wait = false;         // And allow future invocations
            }, limit);
        }
    }
}

The above is fairly straight forward, but let’s discuss it briefly anyway.

The overall solution is to replace the user’s function with our own function. This allows us to add extra logic to the mix, such as how frequently the function can be invoked. This is why our throttle function inevitably returns a new function.

We manage our state with a variable called wait. When wait is true, our door is closed. When wait is false, our door is open. So by switching this value from true to false, we can allow the user’s function to be invoked. And by switching wait from false to true, we prevent any calls to the user function.

Anytime we switch this, we setup a timeout that will toggle it back to false after a period of time. This is where the 200 milliseconds comes in – we’re allowing the user to determine the length of time our door should be shut.

You should also use throttling for function that get called dozens, or hundreds of times. It’s rare that you actually want things to be called that often. The implementation in this post is fairly simple (I was shooting for conciseness), but more complicated solutions exist such as those in lo-dash, underscore, and more.

I created a fiddle with a throttled and and non-throttled callback. Tying this to the window resize event, I adjusted my window width/height briefly and let the number of calls speak for themselves:

Throttled results vs Non-throttled results
Throttled results vs Non-throttled results

More on GIFs and Painting in Internet Explorer

About a week ago I wrote a post demonstrating the use of UI Responsiveness functionality in Internet Explorer 11 to determine how the browser handles animated GIFs in various states. This post was a fairly well-received so I wanted to expand a bit more upon it and cover a few more scenarios.

For the most recent round of testing, I setup a simple interval to change the className of the body element every few seconds. This, in turn, affects the placement and layout of a single image element within the document.

(function () {

  "use strict";

  var states = ["", "opacity", "visibility", "offscreen", "perpendicular"],
      container  = document.body,
      cycles = 0,
      nextState;

  function advanceState () {
    // Advance to next array index, or return to start
    nextState = states[++cycles % states.length];
    // Indicate a new performance mark in our developer tools
    performance.mark(nextState ? "Starting " + nextState : "Restarting");
    // Update the body class to affect rendering of image
    container.className = nextState;
  }

  setInterval(advanceState, 3000);

}());

I used the performance.mark method to add my own indicators in the performance graphs to help me identify when the demo was transitioning into a new state. These performance marks are represented in Internet Explorer by small upside-down orange triangles.

performance.ticks

Let’s walk through each of these triangles left to right, discussing the state they represent.

GIF Untouched

This state is represented by all activity to the left of the first performance mark. Not much needs to be said – Internet Explorer continued to paint the GIF as it sat animated on the screen.

performance.ticks.0

Setting GIF Opacity

This step is represented by all activity between the first and second performance marks. In this step, the image element has its opacity property set to 0. Even though the image is no longer visible, the browser continued repainting the region occupied by the image element.

performance.ticks.1

Setting GIF Visibility

This step is represented by all activity between the second and third performance marks. In this step, the image element has its visibility property set to hidden. Once the visibility property was set to hidden, the browser made one final repaint (presumably to hide the element) and no further paint events took place during the duration of this state.

Of relevance here is that the hidden attribute on the image itself has the same effect. When this attribute is present on the element, Internet Explorer will cease to repaint that elements occupied region.

performance.ticks.2

Setting GIF Outside of View

This step is represented by all activity between the third and fourth performance marks. In this step, the image element is positioned absolutely at top -100% left -100%. In spite of the fact the element is positioned outside of the viewport itself, the browser continued to run paint cycles.

performance.ticks.3

Setting GIF Orientation Perpendicular to Viewport

This step is represented by all activity between the fourth and fifth performance marks (the fifth mark is the ‘Restarting’ mark). In this step, the image is rotated using the transform property so as to set it at a right angle to the viewport, effectively hiding its content from the viewer. This orientation did not affect the browser paint cycle, and Internet Explorer continued repainting the region occupied by the image element.

performance.ticks.4

Conclusion

As a general rule, it appears Internet Explorer will run paint cycles for every animated GIF in the document, unless that element has its visibility property set to hidden. This is fairly reasonable, since setting visibility to hidden is the only explicit way to tell the browser not to render the element. Keep this in mind when performance is of key importance.

After running through and investigating this further I was curious what the same test would reveal in Chrome. I was pleased to see that Chrome would cease to paint for the opacity, visibility, and offscreen configurations. No performance marks are revealed in Chrome’s developer tools, but you can identify the timer functions by the presence of a small orange mark.

performance.ticks.chrome

Tracking GIF Repaints with UI Responsiveness

I recently came across Paul Lewis’ article Avoiding Unnecessary Paints: Animated GIF Edition on HTML5 Rocks and wanted to contribute a bit to the message. If you aren’t a regular reader or HTML5 Rocks I would definitely encourage you to visit often.

The summary of Lewis’ post is that animated GIFs can cause repaints even when obscured by other elements. So even though you may not see the GIF, the browser may continue to repaint every frame of it.

As far as browsers go, Lewis shared with us the “Show paint rectangles” feature in Chrome. When enabled, this feature will visually outline regions that are being repainted. This obviously makes it very easy to determine whether paints are happening on obscured elements. Chrome, Safari, and Opera all repaint. Firefox does not.

In his discussion of various browsers, Lewis calls Internet Explorer 11 a “black box,” suggesting it gives “no indication whether repaints are happening or not.” As a result, no statement was made speculating whether Internet Explorer was in the camp of Chrome, Safari, and Opera, or Firefox.

I quickly did a scan of the comments to see if anybody addressed these words regarding Internet Explorer, but at the time nobody had. I saw this as a great opportunity to introduce my friends to the new UI Responsiveness tool in Internet Explorer 11.

The UI Responsiveness tool in Internet Explorer’s Developer Tools will actually give us pretty granular information about frame-rates, script timing, styling changes, rendering, and even repaints. Given the novelty of this feature in Internet Explorer, I felt it would be good to provide a quick example of how Internet Explorer 11 can indeed tell you whether obscured GIFs cause repaints or not.

A Single Visible GIF

My first experiment consisted of nothing more than a single GIF in the body of my document. By profiling the page for a few seconds I could see that there was constant repainting. This was expected of course, after all there’s a GIF on my screen spinning.

Below is one second of activity. As you can see, constant repainting.

gif.1

Toggling Visibility of a Single GIF

Next up, toggle the visibility of the GIF by way of its display property. I setup a interval to flip the visibility every second. The results were also as expected. For roughly one second, we had constant repainting. Following this we saw a set style event, followed by a single repaint (to hide the element). At this point, it was silence for a second before the element became visible again, and thus began causing additional repaints.

gif.2

Routinely Obscuring a Single GIF

The last experiment was to add another element, a div with a solid background-color in this case, and obscure the animated GIF on an interval. This was done by positioning both the div and the image absolutely within the body, and giving the div a higher z-index.

As can be seen in the image below, repainting did not cease even when the layout was adjusted every second. This demonstrates that when obscured, animated GIFs will continue to cause repaints in Internet Explorer 11. Whether this will be the case for future versions of Internet Explorer remains to be seen.

gif.3

Conclusion

So as we can see in these examples above, Internet Explorer 11 is capable of sharing vital information about costly repaints. Additionally, IE falls into the Chrome, Safari, and Opera camp. It sure would be nice if all browsers followed Firefox’s lead here and stopped repaints on obscured GIFs, but perhaps there is a good reason they haven’t, who knows.

I hope you can see the enormous value the UI Responsiveness panel in Internet Explorer 11’s Developer Tools brings to the debugging experience and use it to make your projects more responsive and performant in the future. The team behind Internet Explorer really have been doing amazing work lately, and the UI Responsiveness functionality is but one example of this.

UPDATE: More on GIFs and Painting in Internet Explorer