Get to know MDN better
It is very important to consider how you are using JavaScript on your websites and think about how to mitigate any performance issues that it might be causing. While images and video account for over 70% of the bytes downloaded for the average website, byte per byte, JavaScript has a greater potential for negative performance impact — it can significantly impact download times, rendering performance, and CPU and battery usage. This article introduces tips and techniques for optimizing JavaScript to enhance the performance of your website.
| Basic software installed, and basic knowledge of client-side web technologies. |
| To learn about the effects of JavaScript on web performance and how to mitigate or fix related issues. |
The first question you should answer before starting to optimize your code is "what do I need to optimize?". Some of the tips and techniques discussed below are good practices that will benefit just about any web project, whereas some are only needed in certain situations. Trying to apply all these techniques everywhere is probably unnecessary, and may be a waste of your time. You should figure out what performance optimizations are actually needed in each project.
To do this, you need to measure the performance of your site. As the previous link shows, there are several different ways to measure performance, some involving sophisticated performance APIs. The best way to get started however, is to learn how to use tools such as built-in browser network and performance tools, to see what parts of the page load are taking a long time and need optimizing.
The most performant, least blocking JavaScript you can use is JavaScript that you don't use at all. You should use as little JavaScript as possible. Some tips to bear in mind:
You should also split your JavaScript into multiple files representing critical and non-critical parts. JavaScript modules allow you to do this more efficiently than just using separate external JavaScript files.
Then you can optimize these smaller files. Minification reduces the number of characters in your file, thereby reducing the number of bytes or weight of your JavaScript. Gzipping compresses the file further and should be used even if you don't minify your code. Brotli is similar to Gzip, but generally outperforms Gzip compression.
You can split and optimize your code manually, but often a module bundler like webpack will do a better job of this.
Before looking at the tips contained in this section, it is important to talk about where in the process of browser page rendering JavaScript is handled. When a web page is loaded:
Note: This is a very simplified account of what happens, but it does give you an idea.
The key step here is Step 3. By default, JavaScript parsing and execution are render-blocking. This means that the browser blocks the parsing of any HTML that appears after the JavaScript is encountered, until the script has been handled. As a result, styling and painting are blocked too. This means that you need to think carefully not only about what you are downloading, but also about when and how that code is being executed.
The next few sections provide useful techniques for optimizing the parsing and execution of your JavaScript.
If a script is really important and you are concerned that it is affecting performance by not being loaded quickly enough, you can load it inside the <head> of the document:
This works OK, but is render-blocking. A better strategy is to use rel="preload" to create a preloader for critical JavaScript:
The preload <link> fetches the JavaScript as soon as possible, without blocking rendering. You can then use it wherever you want in your page:
or inside your script, in the case of a JavaScript module:
Note: Preloading does not guarantee that the script will be loaded by the time you include it, but it does mean that it will start being downloaded sooner. Render-blocking time will still be shortened, even if it is not completely removed.
On the other hand, you should aim to defer parsing and execution of non-critical JavaScript to later on, when it is needed. Loading it all up-front blocks rendering unnecessarily.
First of all, you can add the async attribute to your <script> elements:
This causes the script to be fetched in parallel with the DOM parsing, so it will be ready at the same time and won't block rendering.
Note: There is another attribute, defer, which causes the script to be executed after the document has been parsed, but before firing the DOMContentLoaded event. This has a similar effect to async.
You could also just not load the JavaScript at all until an event occurs when it is needed. This could be done via DOM scripting, for example:
JavaScript modules can be dynamically loaded using the import() function:
When the browser runs your JavaScript, it will organize the script into tasks that are run sequentially, such as making fetch requests, driving user interactions and input through event handlers, running JavaScript-driven animation, and so on.
Most of this happens on the main thread, with exceptions including JavaScript that runs in Web Workers. The main thread can run only one task at a time.
When a single task takes longer than 50 ms to run, it is classified as a long task. If the user attempts to interact with the page or an important UI update is requested while a long task is running, their experience will be affected. An expected response or visual update will be delayed, resulting in the UI appearing sluggish or unresponsive.
To mitigate this issue, you need to break down long tasks into smaller tasks. This gives the browser more chances to perform vital user interaction handling or UI rendering updates — the browser can potentially do them between each smaller task, rather than only before or after the long task. In your JavaScript, you might do this by breaking your code into separate functions. This also makes sense for several other reasons, such as easier maintenance, debugging, and writing tests.
For example:
However, this kind of structure doesn't help with main thread blocking. Since all the five functions are being run inside one main function, the browser runs them all as a single long task.
To handle this, we tend to run a "yield" function periodically to get the code to yield to the main thread. This means that our code is split into multiple tasks, between the execution of which the browser is given the opportunity to handle high-priority tasks such as updating the UI. A common pattern for this function uses setTimeout() to postpone execution into a separate task:
This can be used inside a task runner pattern like so, to yield to the main thread after each task has been run:
To improve this further, we can use Scheduler.yield() where available to allow this code to continue executing ahead of other less critical tasks in the queue:
Animations can improve perceived performance, making interfaces feel snappier and making users feel like progress is being made when they are waiting for a page to load (loading spinners, for example). However, larger animations and a higher number of animations will naturally require more processing power to handle, which can degrade performance.
The most obvious piece of animation advice is to use less animations — cut out any non-essential animations, or consider giving your users a preference they can set to turn off animations, for example if they are using a low-powered device or a mobile device with limited battery power.
For essential DOM animations, you are advised to use CSS animations where possible, rather than JavaScript animations (the Web Animations API provides a way to directly hook into CSS animations using JavaScript). Using the browser to directly perform DOM animations rather than manipulating inline styles using JavaScript is much faster and more efficient. See also CSS performance optimization > Handling animations.
For animations that can't be handled in JavaScript, for example, animating an HTML <canvas>, you are advised to use Window.requestAnimationFrame() rather than older options such as Window.setInterval(). The requestAnimationFrame() method is specially designed for handling animation frames efficiently and consistently, for a smooth user experience. The basic pattern looks like this:
You can find a nice introduction to canvas animations at Drawing graphics > Animations, and a more in-depth example at Object building practice. You can also find a full set of canvas tutorials at Canvas tutorial.
Events can be expensive for the browser to track and handle, especially when you are running an event continuously. For example, you might be tracking the position of the mouse using the mousemove event to check whether it is still inside a certain area of the page:
You might be running a <canvas> game in your page. While the mouse is inside the canvas, you will want to constantly check for mouse movement and cursor position and update the game state — including the score, the time, the position of all the sprites, collision detection information, etc. Once the game is over, you will no longer need to do all that, and in fact, it will be a waste of processing power to keeping listening for that event.
It is, therefore, a good idea to remove event listeners that are no longer needed. This can be done using removeEventListener():
Another tip is to use event delegation wherever possible. When you have some code to run in response to a user interacting with any one of a large number of child elements, you can set an event listener on their parent. Events fired on any child element will bubble up to their parent, so you don't need to set the event listener on each child individually. Less event listeners to keep track of means better performance.
See Event delegation for more details and a useful example.
There are several general best practices that will make your code run more efficiently.
Reduce DOM manipulation: Accessing and updating the DOM is computationally expensive, so you should minimize the amount that your JavaScript does, especially when performing constant DOM animation (see Handling JavaScript animations above).
Batch DOM changes: For essential DOM changes, you should batch them into groups that get done together, rather than just firing off each individual change as it occurs. This can reduce the amount of work the browser is doing in real terms, but also improve perceived performance. It can make the UI look smoother to get several updates out of the way in one go, rather than constantly making small updates. A useful tip here is — when you have a large chunk of HTML to add to the page, build the entire fragment first (typically inside a DocumentFragment) and then append it all to the DOM in one go, rather than appending each item separately.
Simplify your HTML: The simpler your DOM tree is, the faster it can be accessed and manipulated with JavaScript. Think carefully about what your UI needs, and remove unnecessary cruft.
Reduce the amount of looped code: Loops are expensive, so reduce the amount of loop usage in your code wherever possible. In cases where loops are unavoidable:
Avoid running the full loop when it is unnecessary, using break or continue statements as appropriate. For example, if you are searching arrays for a specific name, you should break out of the loop once the name is found; there is no need to run further loop iterations:
Do work that is only needed once outside the loop. This may sound a bit obvious, but it is easy to overlook. Take the following snippet, which fetches a JSON object containing data to be processed in some way. In this case the fetch() operation is being done on every iteration of the loop, which is a waste of computing power. The fetching, which does not depend on i, could be moved outside the loop, so it is only done once.
Run computation off the main thread: Earlier on we talked about how JavaScript generally runs tasks on the main thread, and how long operations can block the main thread, potentially leading to bad UI performance. We also showed how to break long tasks up into smaller tasks, mitigating this problem. Another way to handle such problems is to move tasks off the main thread altogether. There are a few ways to achieve this:
This page was last modified on Nov 7, 2025 by MDN contributors.
Your blueprint for a better internet.
Visit Mozilla Corporation’s not-for-profit parent, the Mozilla Foundation.
Portions of this content are ©1998–2026 by individual mozilla.org contributors. Content available under a Creative Commons license.