At a time where the majority of web browsing is done on a phone or tablet, performance is critical. Not everybody has the latest device, and each delay and stutter could cost a customer. Thankfully, there are plenty of ways to use JavaScript to stop this happening.


Jagged scrolling is a clear sign something is up. In some cases, the browser is being forced to wait because of listeners applied to the page. Events such as ‘wheel’ or ‘touchmove’ are able to cancel scrolling, so the page has to wait
until the event has completed before the default scrolling behaviour can begin. This can cause jerky and inconsistent scrolling, which makes for a poor user experience.

document. addEventListener(‘touchmove’, handler, {passive: true});

To get around this, pass an object as the third parameter when adding an event listener. By marking the event as passive, the browser can assume scrolling will not be afected, so it can start immediately.

This third parameter replaces the ‘useCapture’ option in older browsers, so it is important to use feature detection when making use of this type of listener. To intentionally disable scrolling, applying ‘touch-action: none’ in CSS will help in more browsers.


Events like scrolling and resizing fire as quickly as they can to make sure whatever is listening can stay up to date. If something resource intensive is happening on each event, this can quickly grind a page to a halt.

const resizeDebounce = debounce(() => {
// Code for resize event }, 200);
window. addEventListener(‘resize’, resizeDebounce);

Debouncing is a technique that throttles how often the callback to one of these events is called. The implementation of a debounce function and how often the function gets called will vary by project, but reducing the events to five times a second, for example, will see an instant improvement on the page.


A common use of the scroll event is to detect when an element comes into view on the page. Even with debouncing, calling getBoundingClientRect() requires the browser to reanalyse the layout of the entire page. There is a new browser API called IntersectionObserver, which reports on the visibility of observed elements by calling a function whenever they enter or exit the viewport. For infinite scrolling sites, this can be used as a flag to remove or recycle older views.

IntersectionObserver is available in all the latest browsers except Safari. It’s worth using this API and falling back to older techniques, as the diference is vastly noticeable.


When working with large datasets or processing big files like images, JavaScript can quickly lock up the browser window. All the work is getting performed on a single thread, so if that thread is busy the interface cannot update.

If you know a process is going to take a long time to run, it is a good idea to put it inside a web worker. These are scripts that run on a separate thread, which leaves the user interface running smoothly. Scripts can talk to each other through a special message method. Web workers don’t have access to the DOM and some properties on the window object, so these messages can be used to pass the necessary information.


Use the browser’s tools to find why a page is performing badly

All modern browsers will record a profile of a page. Chrome has a separate profiler for JS, Firefox has a ‘JS flame chart’ under the Performance tab, and Safari records everything in ‘Timelines’.

These can be used to see what’s being called when and why. To test specific issues, start recording, perform the slow action, and stop recording. After a few seconds, the tools will show a chart with details.

3. MAKE SMALL CHANGES AND REPEAT Once you have identified the issue and looked into what might be causing it, make a small change and run the profiler again. By keeping a note of how much improvement each change is making, you can be sure you’re on the right track.
JS can cause issues with page rendering, such as paint thrashing. Make sure these are iterated through as well. They are often highlighted diferently to JS issues.

2. ISOLATE WHAT’S CAUSING THE ISSUE Each browser will display a slightly diferent version of a flame chart. These show small coloured blocks that stack on top of each other. Each block will represent a function call that happened during the recording.

Long blocks are a cause for concern, as these took the longest to run. Hover over or click into each one to see where this code was called and how long each one took.

Leave a Reply

Your email address will not be published. Required fields are marked *