Software

How Does JavaScript Affect Site Speed? A Practical Guide to JavaScript Performance

Talha AslanTalha Aslan 18 min read 1 views

JavaScript performance is about how much time the browser spends downloading, parsing and running your scripts before a page looks ready and responds to taps. I have worked on client sites since 2012. In most slow sites I audit, the real culprit is not images. It is JavaScript that grew without anyone keeping count. This guide explains where that cost comes from and how I cut it, step by step.

I cover the wider ranking impact of speed in how site speed affects SEO. I also walk through testing in my Lighthouse performance test guide. Here the focus stays on JavaScript alone: how the browser handles it, where it gets stuck and what you can change.

How does JavaScript affect site speed and JavaScript performance?

JavaScript is code that runs on the browser's main thread, and while it runs, the page cannot paint, scroll smoothly or respond to clicks. So the heavier your scripts are, the later the page appears and the slower it reacts. Good JavaScript performance means keeping that blocked time short.

For example, compare it with an image. The browser only downloads and decodes a 300 KB image. However, a 300 KB script has to be downloaded, parsed, compiled and then executed. As a result, byte for byte, JavaScript costs far more. Most of that work also happens on the same thread that handles user input.

The pattern I see in the field is almost always the same. A site launches fast. Then every campaign adds a pixel and every new need adds a plugin. A year later the page loads dozens of scripts nobody can fully list. In short, JavaScript problems rarely come from one big mistake. They come from accumulation.

What does the browser do with a JavaScript file?

You can think of the work in four stages. Each stage has its own cost, and each optimization targets one of them.

  1. Download. The file travels over the network. Size, compression and caching matter here.
  2. Parse and compile. The engine reads the code and prepares it to run. On mid-range phones this step takes noticeable time.
  3. Execute. The code runs on the main thread. It changes the DOM and attaches event listeners.
  4. Aftermath. Style recalculation, layout and paint follow whatever the code changed.

Above all, the critical point is that the main thread does one thing at a time. The web.dev guide on optimizing long tasks defines any task over 50 milliseconds as a long task. If a user taps a button during a long task, the browser cannot handle that tap until the task ends. Therefore you should measure execution time, not just file size.

What is a render-blocking script?

A render-blocking script is a classic script tag in the head without async or defer. When the browser meets one, it stops reading the HTML. It fetches the file, runs it and only then continues building the page.

As a result, on a slow connection the visitor stares at a blank or half-built screen for seconds. Moreover, that script often has nothing to do with the first view. For example, a chat widget, an analytics library or a slider plugin often loads synchronously in the head. Still, none of them needs to run before the top of the page appears.

Lighthouse flags this under "Eliminate render-blocking resources". When I first look at a site, I open the source and count the script tags in the head. Then I ask one question for each: must this code run before the visitor sees the top of the page? The answer is nearly always no.

What is the difference between defer and async?

First, both attributes let the browser download a script without pausing HTML parsing. The difference lies in when the script runs. The MDN script reference covers the details. I summarised them in the table below.

MethodDownloadWhen it runsKeeps order?Best use
Plain script in headBlocks parsingImmediatelyYesAlmost never
asyncIn parallelAs soon as it arrivesNoIndependent scripts, analytics
deferIn parallelAfter HTML parsing endsYesYour own application code
type="module"In parallelDeferred by defaultYesModern module setups
Load on interactionOn user actionWhen neededHandled in codeChat, maps, video players

So if your scripts depend on each other, use defer, because it keeps the order. For a measurement tag with no dependencies, async works fine. In practice, I load the site's own code with defer. Third party tags go async or load later wherever possible.

Where should you start improving JavaScript performance?

Start with an inventory. Without knowing why each script loads, every fix is a guess. I build the inventory in this order:

  • In the Chrome DevTools Network tab, I filter by JS and list every file with its size and origin.
  • In the Coverage panel, I check how much code goes unused on page load.
  • In the Performance panel, I record a load and mark which file owns each long task.
  • For every third party tag, I name an owner. Who asked for it, and does anyone still use it?

This list usually surprises people. For instance, a pixel from a campaign that ended two years ago still fires. Or the same analytics code runs twice, once from the theme and once from the tag manager. Consequently, JavaScript performance work often starts with deleting code, not writing it. That is the cheapest and fastest win you will get.

How do you find and remove unused JavaScript?

Put simply, unused JavaScript is code that loads on a page but never runs there. A typical case is a form validation library that only the contact page needs, yet every page loads it. The Coverage panel shows this ratio per file with red and green bars.

I clean up in three ways. First, I remove plugins and libraries nobody uses. Next, I move page specific code to the pages that need it. Finally, if the site uses only a small part of a big library, I import that part alone or replace it with a built-in browser feature.

One warning, though. Coverage only reflects the session you recorded. If you never opened the menu, the menu code looks unused. That said, you should click through every interaction before you delete anything. Otherwise you end up with a faster site whose menu no longer opens.

What is code splitting and when does it help?

Code splitting means breaking one large bundle into smaller chunks by page or feature. The visitor then downloads only the code they need right now. Modern bundlers do this automatically through dynamic imports.

In practice, it helps most on single page apps and on sites built with frameworks like React or Vue. For example, a home page visitor should never receive the admin panel, a charting library or the checkout logic. Route based splitting solves most of this.

However, over-splitting creates its own problems. Dozens of tiny chunks mean more requests and longer dependency chains. I usually start with route based splitting. After that, I split out only the truly heavy components, such as maps, rich text editors or video players. If you want the architectural view for large teams, see my piece on micro frontends.

How much do third party scripts slow a site down?

In short, third party scripts come from someone else's servers. Think ad pixels, analytics, chat tools, heatmaps, A/B testing tools and embedded videos. The core problem is control. You do not decide their size or behaviour, and when the vendor updates the file, your cost changes too.

I cannot give you a fixed slowdown figure. The impact varies a lot by tag type and loading method. Still, I see one pattern again and again: a large share of long tasks on the main thread comes from third party tags rather than the site's own code. This is a field observation, not a guarantee, and you need to measure it on each site.

In the Performance panel, group activity by third party. You will see how much main thread time each domain uses. That list is the most concrete document you can bring to a meeting with the marketing team. Instead of saying "this pixel slows the page", you can say "this pixel costs this much time on every load".

How do you manage third party tags without hurting speed?

Removing marketing tags is not always an option. Without conversion tracking, you cannot manage an ad budget. So the goal is not to delete tags but to load them at the right time and in the right place. These are the rules I apply:

  • Each tag runs only where it is needed. For example, the purchase pixel fires on the thank you page only.
  • Heavy widgets like chat, maps and video show a light preview until the user clicks.
  • If two tools do the same job, one goes. You rarely need two heatmap tools.
  • Every tag in the tag manager has an owner and a review date.
  • Non-critical tags fire after the page finishes loading.

Watch one trade-off here. If you delay a conversion tag too long, you may miss conversions from visitors who leave quickly. Therefore check for tracking loss whenever you defer measurement. In the accounts where I run Google Ads management, I track speed and conversion data side by side to hold that balance.

How does JavaScript relate to INP?

INP, or Interaction to Next Paint, measures how long it takes for the screen to update after a click, tap or key press. According to the web.dev INP guide, 200 milliseconds or less counts as good. JavaScript is the most direct driver of this metric.

Specifically, the delay of an interaction has three parts. There is input delay, then the time your event handler runs, then the presentation delay before the next paint. Input delay grows when the main thread is busy with another long task at the moment of the tap. Handler time is simply the weight of your own code. In other words, JavaScript sits behind both.

That is why a site with a good LCP can still have a poor INP. The page appears quickly. Then you press "add to cart" and nothing happens for half a second. The user assumes the click failed and taps again. I discuss how this friction hurts sales in SEO and UX page experience factors.

How can you break up long tasks?

Breaking up a long task means turning one 300 millisecond job into smaller pieces with breathing room in between. If the user taps during that time, the browser can handle the tap between pieces.

The method web.dev recommends is to add deliberate yield points. In Chrome, scheduler.yield() pauses your work, hands control back to the browser and queues the rest with priority. For browsers without support, you can write a fallback with setTimeout. The key is not to yield after every line. Instead, yield between user-facing work and background work.

Here is a practical example. Picture a filter button handler that updates the product list, sends an analytics event and rewrites the URL. First, you update the list. Then you yield. After that, you handle analytics and the URL. The user sees the result at once, and the rest finishes at a moment they will not notice.

How does your framework choice affect JavaScript performance?

Above all, your framework decides up front how much JavaScript a page ships. A fully client-rendered single page app must download and run the framework and the app code before it shows content. Server-rendered or statically generated pages, by contrast, send ready HTML.

This does not mean React or Vue is bad. But if a corporate brochure site needs about as much interactivity as a calculator, shipping a full app framework to every visitor is an expensive choice. The "islands" approach, now common, hydrates only the interactive parts of a page. The rest stays plain HTML.

My advice: choose the framework based on how interactive the page really is, not on team habit. In web design projects, I raise this question in the first meeting. Changing the framework later costs far more than choosing well at the start.

How does JavaScript rendered content affect SEO?

In its JavaScript SEO basics documentation, Google explains that it renders pages with an evergreen Chromium. It also explains that rendering happens in a separate queue after crawling. So if content only appears after JavaScript runs, Google seeing it depends on that extra step.

The issues I meet most often are these. Links use click handlers instead of real anchor tags. Titles and descriptions exist only on the client side. Error pages return a 200 status. None of these is a speed issue as such. Still, they grow from the same root: too much dependence on JavaScript.

For that reason, keep key content, headings and internal links in the HTML the server sends. I cover the crawling side in technical SEO tips and technical SEO after AI. Also keep in mind that many AI crawlers do not run JavaScript at all.

Which techniques shrink your bundle size?

When you cannot delete or split code any further, ship what remains as small as possible. At this point JavaScript performance work turns more technical. These are the core techniques I use:

  1. Minification. It strips whitespace, comments and long variable names. Most build tools apply it in production mode.
  2. Compression. Serving scripts with Brotli or gzip cuts transfer size a lot.
  3. Tree shaking. The bundler leaves out exports nobody imports. It needs ES modules.
  4. Polyfill cleanup. Keep your browser target list current, so modern browsers do not receive patches meant for old ones.
  5. Library swaps. Replace heavy date or animation libraries with built-in browser APIs or smaller options.

Remember one thing. Compression reduces transfer size, not execution cost. The browser still parses and runs the full uncompressed code. So treat compression as basic hygiene, not as the final fix.

How do caching and resource hints speed up script loading?

For a returning visitor, the fastest file is the one that never downloads. That is why you give script files content-hashed names and long cache lifetimes. When a file changes, its name changes too, so nobody gets stuck on an old version.

Resource hints help on the first visit. For example, a preconnect to a critical third party domain starts the connection early. For a module the page needs right away but the browser discovers late, you can use modulepreload.

On the other hand, adding hints everywhere backfires. Every preload tells the browser "fetch this now" and competes for bandwidth. As a result, when everything is a priority, nothing is. I usually keep the preload list to two or three items. Then I measure each one before I keep it.

Why is JavaScript a bigger problem on mobile?

Developers mostly test on powerful laptops, however. Yet many visitors arrive on mid-range phones. Parsing and running the same script takes clearly longer on a weaker processor.

So an interaction that feels smooth on desktop can stutter on a phone. CPU throttling in Chrome DevTools gives you a rough idea of the gap. Still, it does not replace testing on a real device. I always keep an older mid-range Android phone on my desk for this.

Mobile networks add to the problem. When downloads take longer, every render-blocking script leaves the visitor with a blank screen for longer. For a full mobile check, see my mobile friendly test guide. Put simply, for mobile visitors JavaScript performance is not a nice extra. It is a basic requirement.

I also keep a short mobile checklist. First, I count the scripts needed to paint the first screen on a phone. Next, I test the touch menu, filters and cart button with a throttled CPU. Finally, I check whether code for components that never show on mobile still loads. A desktop mega menu, for instance, often ships its full code to phones as well.

Which tools measure JavaScript performance?

There are two kinds of data: lab data and field data. Lab data simulates one load in a controlled setting. Field data comes from real users. They answer different questions, so you need both.

  • Lighthouse gives a fast diagnosis for Total Blocking Time, unused JavaScript and render-blocking resources.
  • Chrome DevTools Performance shows how long each function takes, down to the millisecond.
  • PageSpeed Insights shows lab results and, if your site has enough traffic, real Chrome user data on one page.
  • Search Console lists groups of problem URLs in its Core Web Vitals report.

One detail matters here. INP is a field metric, and a lab test like Lighthouse, which does not click anything, cannot measure it directly. In the lab, TBT is a good hint of how busy the main thread is. For real INP, though, look at field data. My Search Console guide explains how to read that report step by step.

What are the most common JavaScript optimization mistakes?

In practice, over the years I have seen the same mistakes on many different sites. These are the most common ones:

  • Chasing the Lighthouse score and never looking at real user data.
  • Installing a speed plugin that defers every script blindly. This can break menus, forms and checkout.
  • Lazy loading critical content that JavaScript injects above the fold.
  • Treating the tag manager as a bottomless drawer.
  • Optimizing once and never reviewing new code after that.

What these share is deciding without measuring. That is why I measure before and after every change, under the same conditions. I also change one thing at a time. If you change five things at once, you cannot tell which one helped and which one broke something.

How do you plan the work on an older site?

On a site that grew for years, fixing everything at once rarely works. So I sort the work by risk first. Changes that touch revenue, such as checkout, contact forms and navigation, come last. Unneeded code on content pages goes in the first week.

My second rule is to keep every change reversible. For instance, before deleting a tag, I pause it in the tag manager and watch conversion data for a week. If nothing breaks, I remove it for good. That way you gain speed without putting the marketing team's tracking at risk.

The third rule is to speak the same language as the team. Developers say "main thread", marketers say "pixel" and managers say "sales". Therefore I log each finding in three columns: what slows the page, who owns it and which measurement changes if it goes. This turns a technical topic into a list people can decide on.

Finally, set realistic timing. On a small corporate site, the first cleanup can take a few days. On a large online shop, the same job can stretch over weeks. These ranges come from field experience and are a starting point, not a guarantee.

How do you keep JavaScript performance from sliding back?

However, a one-off cleanup melts away within months. For lasting results, you need a process. The most effective tool is a performance budget. For example, you set an upper limit on how much JavaScript the home page may ship on first load and how many long tasks it may have.

Then you tie that budget to your release process. The build tool warns when the bundle exceeds the limit. Before anyone adds a new third party tag, a short approval step runs. Speed then changes through deliberate decisions, not by accident.

Finally, make a monthly check of field data a habit. The trend in Search Console or PageSpeed Insights usually reveals the effect of a new plugin or campaign tag quickly. On sites where I provide SEO consulting, this check is part of the monthly report.

In what order should you tackle JavaScript performance?

If I turn everything above into one workable sequence, this is the path I follow in the field:

  1. Build an inventory of each script's source, size and owner.
  2. Delete what you do not need. The biggest and cheapest gain comes from here.
  3. Load render-blocking scripts with defer or async.
  4. Limit third party tags by page and by timing.
  5. Apply route based code splitting.
  6. Break up long tasks and lighten interaction handlers.
  7. Configure minification, compression and caching properly.
  8. Set a performance budget and track field data every month.

The logic is simple. Steps that bring cost to zero come first. Steps that reduce cost come next. The process that protects the gains comes last. If you want help applying this to your own site, you can reach me through the contact page. We first measure where you stand. Then we decide together which step will pay off most for you.

Frequently Asked Questions

Will removing all JavaScript make my site faster?
Yes, but for most sites it is not a realistic goal. Menus, form validation, carts and tracking all need JavaScript. The better approach is to defer code the first screen does not need, delete what is unnecessary and ship the rest in small chunks. That way you keep functionality while cutting the load noticeably.
Should I use defer or async?
For your own site code, defer is usually the safer choice. It keeps scripts in order and runs them after HTML parsing ends. For analytics or measurement tags with no dependencies, async is enough. If you give async to scripts that depend on each other, the load order can change and cause errors.
Does a speed plugin fix JavaScript problems?
Partly. Plugins automate minification, bundling and deferral, but they cannot decide which scripts you actually need. Deferring everything blindly can also break menus or checkout. Use the plugin, but first build an inventory, remove unnecessary code by hand and verify the result with measurements.
Why is my INP poor when my Lighthouse score is high?
A default Lighthouse run loads the page but does not click like a user, so it does not measure INP directly. Real users interact during and after loading. Heavy event handlers and background third party code delay those interactions. Check field data and record a DevTools Performance trace to find the cause.
Does Google Tag Manager slow down a website?
The container itself is a light loader. The real cost comes from the tags inside it. Each tag can download its own script and run on the main thread. So review your tags regularly, fire each one only on the pages that need it and remove the ones nobody uses. You keep tracking and cut the load.
#JavaScript#Site Speed#INP#Core Web Vitals#Technical SEO#Web Performance
Share:
Talha Aslan
Talha Aslan

Google Partner digital marketing expert. Hands-on with SEO, Google Ads, web design and e-commerce projects since 2012; every post here comes from that experience.

Next project

Let's talk about your project.

No middlemen, no layers: you talk directly to the expert doing the work. The first consultation is free, I listen to your goal and come back with a clear roadmap.

WhatsApp Call Now