NEWAI content checker: see which pages read like AI text

Knowledge baseWebsite speed

Defer JavaScript

defer on a script tag lets the browser download the file while it builds the page, and run it once the HTML is done, in order. The page shows without waiting for that script. All it takes is access to your theme's HTML or a switch in your caching plugin, plus a few minutes of testing.

Updated Oct 30, 20264 min read

What does defer do?

A normal script in the <head> holds everything up: the browser downloads and runs it before it reads on. On a slow phone, that's a white screen. One word lets the browser fetch the file while it keeps reading:

<script src="/js/slider.js" defer></script>

The script then runs after the HTML is parsed, just before the DOMContentLoaded event, so it can use the page and any deferred script above it. Defer does nothing on inline code, and scripts with type="module" are deferred already.

Async also downloads while the page is built, but runs the moment the file arrives, in any order. Which one helps which Core Web Vital is in the long version on corewebvitals.io.

How much faster does the page get?

In a test on marketingtracer.com, one ordinary library in the head cost the homepage about 0.6 seconds of first paint on a slow phone, and defer gave it all back. The library was jQuery 3.7.1, loaded the way many WordPress themes do. Chrome played a phone with a slowed-down processor on slow 4G, nine runs each. Median first paint: 948 ms as is, 1,572 ms with jQuery blocking, 944 ms with it deferred.

Bar chart: first paint of the marketingtracer.com homepage on a slow phone, 948 ms as is, 1,572 ms with jQuery blocking in the head, 944 ms with the same script deferred

Lab test, October 29, 2026: one script loaded two ways.

That's one library on one page in a lab: a head full of plugin scripts loses more, a desktop on fiber far less. On marketingtracer.com and my four other sites, no script sits in the <head>. Each site's own small file, a few kilobytes compressed, loads with defer and starts the rest when needed.

Defer JavaScript in four steps

  1. Find the blocking scripts. In PageSpeed Insights, open "Render-blocking requests" (formerly "Eliminate render-blocking resources"). In the page source, every <script src> in the <head> without defer, async or type="module" blocks. Stylesheets in the head block too: see inline CSS. One page per template is enough.
  2. Add defer. By hand, it's the one word above. In WordPress, WP Rocket's "Load JavaScript deferred" adds it to every JavaScript file, and other caching plugins have a similar switch. Since WordPress 6.3 a theme developer can also pass a strategy to wp_enqueue_script. On Shopify, defer the non-critical scripts in the theme, and remove or defer the app scripts that block the page.
  3. Click through everything that uses JavaScript: the phone menu, forms, sliders, maps, cart, checkout, cookie banner, logged out with an empty cache. A red "is not defined" in the console (F12) means a script ran before the one it needs.
  4. Measure again. The file should be gone from "Render-blocking requests". For a whole site, MarketingTracer's SEO audit has a Speed column under Pages: a lab test of the pages the crawl found. With Search Console connected, their clicks from Google sit next to it, so you see which pages were slow and whether they got faster. It doesn't list blocking scripts; that's step 1.

Why did my site break after deferring?

A site breaks after deferring when code runs before the library it needs. Deferred files keep their order among themselves. The trouble is code that isn't deferred, like inline code: it still runs where it stands. That's how a map or a slider vanishes, with "jQuery is not defined" in the console. A test page with these two scripts throws that error in Chrome, and its slider stays hidden:

<script src="/js/jquery.min.js" defer></script>
<script>
  jQuery('.slider').show();
</script>

Make the inline code wait for DOMContentLoaded, which fires after the deferred scripts have run, and it works:

<script>
  document.addEventListener('DOMContentLoaded', function () {
    jQuery('.slider').show();
  });
</script>

WP Rocket adds that wrapper itself for inline jQuery it recognizes. When a plugin writes the inline code, leave that library blocking and defer the rest, as WP Rocket advises for jQuery. You lose a little speed, and the checkout keeps working.

Defer, async or delay?

Defer your own scripts and anything that touches the page or another script: menus, forms, jQuery plugins. Analytics can stay async; Google's tag already comes that way.

Can you just defer every script? It depends a lot. Defer is really the minimum, but then you have to test properly: does everything still work? Not every script may be deferred, like some A/B tests and sliders that change a lot on screen; if you have those, you have a different problem to fix first.

Then there are scripts the first view doesn't need: chat widgets, exit-intent pop-ups, the Facebook and TikTok pixels. Those can wait for the load event, when the browser has loaded the page and its images, which is still early. WP Rocket's "Delay JavaScript execution" holds scripts back until the visitor moves the mouse, taps, scrolls or presses a key. I'd never wait that long. Delayed analytics never runs for someone who doesn't scroll or tap.

Keep reading

Free 14-day trial

MarketingTracer smart A.I. tool shows you what you need to rank. Then we'll help you get it done.

  • No credit card required
  • No installation needed
  • No strings attached
Start your 14-day trial