Request Waterfall Issues | Blue Frog Docs

Request Waterfall Issues

Optimize request chains and eliminate waterfall loading patterns

Request Waterfall Issues

What This Means

A request waterfall occurs when resources are loaded sequentially rather than in parallel. This causes:

How to Diagnose

Chrome DevTools Waterfall

  1. DevTools > Network tab
  2. Reload page
  3. Analyze the waterfall chart
  4. Look for:
    • Long chains of dependent requests
    • Resources waiting for others to complete
    • Large gaps between requests

Key Metrics to Check

Pattern Problem
Staircase pattern Sequential loading
Large gaps Blocking resources
Late critical resources Priority issues
Third-party chains External dependencies

WebPageTest Analysis

  1. Run test at webpagetest.org
  2. View waterfall chart
  3. Check "Connection View" for parallel request limits

General Fixes

Preconnect to Critical Origins

<!-- Establish early connections -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://cdn.example.com" crossorigin>
<link rel="dns-prefetch" href="https://analytics.example.com">

Preload Critical Resources

<!-- Preload LCP image -->
<link rel="preload" as="image" href="/hero.webp">

<!-- Preload critical font -->
<link rel="preload" as="font" href="/fonts/main.woff2"
      type="font/woff2" crossorigin>

<!-- Preload critical CSS -->
<link rel="preload" as="style" href="/critical.css">

Inline Critical CSS

<!-- Inline above-the-fold CSS -->
<style>
  /* Critical CSS inlined here */
  body { margin: 0; font-family: system-ui; }
  .hero { height: 100vh; display: flex; }
</style>

<!-- Load rest asynchronously -->
<link rel="preload" as="style" href="/main.css"
      onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/main.css"></noscript>

Eliminate Render-Blocking Scripts

<!-- Bad: Blocking script -->
<script src="/app.js"></script>

<!-- Good: Async for independent scripts -->
<script async src="/analytics.js"></script>

<!-- Good: Defer for dependent scripts -->
<script defer src="/app.js"></script>

<!-- Good: Module scripts (deferred by default) -->
<script type="module" src="/app.js"></script>

Optimize Third-Party Loading

// Delay non-critical third-parties
function loadThirdParties() {
  // Load after user interaction or delay
  const scripts = [
    'https://analytics.example.com/script.js',
    'https://chat.example.com/widget.js'
  ];

  scripts.forEach(src => {
    const script = document.createElement('script');
    script.src = src;
    script.async = true;
    document.body.appendChild(script);
  });
}

// Trigger on interaction
['mousedown', 'touchstart', 'scroll'].forEach(event => {
  window.addEventListener(event, loadThirdParties, { once: true });
});

// Fallback after delay
setTimeout(loadThirdParties, 5000);

Bundle Optimization

// webpack.config.js
module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        // Separate vendor bundle
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          priority: 10
        },
        // Common chunks
        common: {
          minChunks: 2,
          priority: 5,
          reuseExistingChunk: true
        }
      }
    }
  }
};

HTTP/2 Optimization

# Enable HTTP/2 server push (use sparingly)
location / {
    http2_push /styles/critical.css;
    http2_push /scripts/app.js;
}

# Or use Link headers
add_header Link "</styles/critical.css>; rel=preload; as=style";

Image Loading Priority

<!-- High priority: LCP image -->
<img src="/hero.webp" fetchpriority="high" alt="Hero">

<!-- Low priority: Below-fold images -->
<img src="/footer-bg.webp" fetchpriority="low" loading="lazy" alt="">

Avoid CSS @import Chains

/* Bad: Creates waterfall */
@import url('fonts.css');
@import url('layout.css');
@import url('components.css');

/* Good: Combine or use link tags */
<!-- Better: Parallel loading -->
<link rel="stylesheet" href="fonts.css">
<link rel="stylesheet" href="layout.css">
<link rel="stylesheet" href="components.css">

JavaScript Dynamic Import

// Split code to avoid loading everything upfront
// Only load when needed
async function loadChartLibrary() {
  const { Chart } = await import('./chart-library.js');
  return new Chart(document.getElementById('chart'));
}

// Load on demand
document.getElementById('show-chart').onclick = async () => {
  const chart = await loadChartLibrary();
  chart.render(data);
};

Platform-Specific Guides

Platform Guide
WordPress WordPress Performance
Shopify Shopify Speed
Next.js Next.js Optimization

Verification

  1. DevTools waterfall shows parallel loading
  2. Critical resources load early
  3. No long dependency chains
  4. LCP occurs within 2.5s

Further Reading

// SYS.FOOTER