Back to blog
PerformanceJanuary 1, 2024· 14 min read

HTTP/2 and HTTP/3 Performance Analysis: A Developer's Guide

A practical Fusebox guide to http/2 and http/3 performance analysis.

HTTP/2 and HTTP/3 Performance Analysis: A Developer's Guide

The evolution from HTTP/1.1 to HTTP/2 and now HTTP/3 represents one of the most significant performance improvements in web technology. While HTTP/1.1 served us well for decades, modern web applications demanded better. Google found that HTTP/2 reduced page load times by up to 50%, while HTTP/3 promises even greater improvements by solving head-of-line blocking at the transport layer.

Why HTTP Protocol Versions Matter

In 2015, when Google made HTTP/2 a ranking factor, sites that didn't upgrade saw their competitors gain an edge. Today, with HTTP/3 adoption growing rapidly, understanding these protocols isn't optional—it's essential for maintaining competitive web performance.

HTTP Protocol Detection

Start by detecting which HTTP version a site supports:

// HTTP Protocol Version Detector
const HTTPVersionDetector = {
    // Detect HTTP version from current page
    async detectCurrentVersion() {
        const resources = performance.getEntriesByType('resource');
        const navigation = performance.getEntriesByType('navigation')[0];
        
        const results = {
            pageProtocol: navigation?.nextHopProtocol || 'unknown',
            resourceProtocols: {},
            summary: {
                http2: 0,
                http3: 0,
                http1: 0,
                unknown: 0
            }
        };
        
        // Analyze resource protocols
        resources.forEach(resource => {
            const protocol = resource.nextHopProtocol;
            const domain = new URL(resource.name).hostname;
            
            if (!results.resourceProtocols[domain]) {
                results.resourceProtocols[domain] = new Set();
            }
            
            if (protocol) {
                results.resourceProtocols[domain].add(protocol);
                
                // Categorize protocols
                if (protocol.includes('h3') || protocol.includes('quic')) {
                    results.summary.http3++;
                } else if (protocol.includes('h2')) {
                    results.summary.http2++;
                } else if (protocol.includes('http/1')) {
                    results.summary.http1++;
                } else {
                    results.summary.unknown++;
                }
            }
        });
        
        // Convert Sets to Arrays for display
        Object.keys(results.resourceProtocols).forEach(domain => {
            results.resourceProtocols[domain] = Array.from(results.resourceProtocols[domain]);
        });
        
        return results;
    },
    
    // Test specific endpoint for HTTP/2 and HTTP/3 support
    async testEndpoint(url) {
        const results = {
            url,
            protocols: {
                http1: false,
                http2: false,
                http3: false
            },
            features: {},
            performance: {}
        };
        
        try {
            // Make a test request
            const startTime = performance.now();
            const response = await fetch(url, {
                method: 'GET',
                cache: 'no-store'
            });
            const endTime = performance.now();
            
            results.performance.responseTime = endTime - startTime;
            
            // Get protocol from performance API
            const entries = performance.getEntriesByName(url);
            const lastEntry = entries[entries.length - 1];
            
            if (lastEntry?.nextHopProtocol) {
                const protocol = lastEntry.nextHopProtocol;
                
                if (protocol.includes('h3') || protocol.includes('quic')) {
                    results.protocols.http3 = true;
                    results.detectedProtocol = 'HTTP/3';
                } else if (protocol.includes('h2')) {
                    results.protocols.http2 = true;
                    results.detectedProtocol = 'HTTP/2';
                } else if (protocol.includes('http/1')) {
                    results.protocols.http1 = true;
                    results.detectedProtocol = 'HTTP/1.1';
                }
                
                results.protocolString = protocol;
            }
            
            // Check response headers for alt-svc (HTTP/3 support)
            const altSvc = response.headers.get('alt-svc');
            if (altSvc) {
                results.features.altSvc = altSvc;
                if (altSvc.includes('h3')) {
                    results.protocols.http3Available = true;
                }
            }
            
            // Server push detection (HTTP/2 feature)
            const link = response.headers.get('link');
            if (link && link.includes('rel=preload')) {
                results.features.serverPush = true;
            }
            
        } catch (error) {
            results.error = error.message;
        }
        
        return results;
    },
    
    // Analyze HTTP/2 specific features
    analyzeHTTP2Features() {
        const features = {
            multiplexing: false,
            serverPush: false,
            headerCompression: false,
            streamPrioritization: false,
            binaryFraming: true // Always true for HTTP/2
        };
        
        // Check for multiplexing by analyzing concurrent requests
        const resources = performance.getEntriesByType('resource');
        const domains = {};
        
        resources.forEach(resource => {
            const domain = new URL(resource.name).hostname;
            if (!domains[domain]) {
                domains[domain] = [];
            }
            
            domains[domain].push({
                start: resource.startTime,
                end: resource.responseEnd,
                protocol: resource.nextHopProtocol
            });
        });
        
        // Detect multiplexing
        Object.entries(domains).forEach(([domain, requests]) => {
            const http2Requests = requests.filter(r => r.protocol?.includes('h2'));
            
            if (http2Requests.length > 1) {
                // Check for overlapping requests (multiplexing)
                for (let i = 0; i < http2Requests.length; i++) {
                    for (let j = i + 1; j < http2Requests.length; j++) {
                        const r1 = http2Requests[i];
                        const r2 = http2Requests[j];
                        
                        if ((r1.start <= r2.start && r2.start <= r1.end) ||
                            (r2.start <= r1.start && r1.start <= r2.end)) {
                            features.multiplexing = true;
                            break;
                        }
                    }
                }
            }
        });
        
        return features;
    },
    
    // Analyze HTTP/3 specific features
    analyzeHTTP3Features() {
        const features = {
            zeroRTT: false,
            connectionMigration: false,
            improvedCongestionControl: true,
            noHeadOfLineBlocking: true,
            udpBased: true
        };
        
        // Check for 0-RTT by analyzing connection timing
        const resources = performance.getEntriesByType('resource');
        const http3Resources = resources.filter(r => 
            r.nextHopProtocol?.includes('h3') || r.nextHopProtocol?.includes('quic')
        );
        
        http3Resources.forEach(resource => {
            // If connection time is 0, might be 0-RTT
            if (resource.connectEnd - resource.connectStart === 0 && 
                resource.secureConnectionStart === 0) {
                features.zeroRTT = true;
            }
        });
        
        return features;
    }
};

// Test current page
HTTPVersionDetector.detectCurrentVersion().then(console.log);

Performance Comparison Tool

Compare performance across HTTP versions:

// HTTP Version Performance Comparison
class HTTPPerformanceComparison {
    constructor() {
        this.results = {
            http1: { requests: [], metrics: {} },
            http2: { requests: [], metrics: {} },
            http3: { requests: [], metrics: {} }
        };
    }
    
    // Analyze current page performance by protocol
    analyzePage() {
        const resources = performance.getEntriesByType('resource');
        
        resources.forEach(resource => {
            const protocol = resource.nextHopProtocol;
            let version = 'unknown';
            
            if (protocol?.includes('h3') || protocol?.includes('quic')) {
                version = 'http3';
            } else if (protocol?.includes('h2')) {
                version = 'http2';
            } else if (protocol?.includes('http/1')) {
                version = 'http1';
            }
            
            if (version !== 'unknown') {
                this.results[version].requests.push({
                    url: resource.name,
                    duration: resource.duration,
                    size: resource.transferSize,
                    timing: {
                        dns: resource.domainLookupEnd - resource.domainLookupStart,
                        tcp: resource.connectEnd - resource.connectStart,
                        ssl: resource.secureConnectionStart > 0 ? 
                             resource.connectEnd - resource.secureConnectionStart : 0,
                        ttfb: resource.responseStart - resource.requestStart,
                        download: resource.responseEnd - resource.responseStart
                    }
                });
            }
        });
        
        // Calculate metrics for each protocol
        Object.keys(this.results).forEach(version => {
            this.calculateMetrics(version);
        });
        
        return this.generateComparison();
    }
    
    // Calculate performance metrics
    calculateMetrics(version) {
        const requests = this.results[version].requests;
        
        if (requests.length === 0) {
            this.results[version].metrics = { noData: true };
            return;
        }
        
        const metrics = {
            totalRequests: requests.length,
            totalSize: requests.reduce((sum, r) => sum + (r.size || 0), 0),
            totalDuration: requests.reduce((sum, r) => sum + r.duration, 0),
            avgDuration: 0,
            avgTTFB: 0,
            avgDownloadTime: 0,
            concurrentRequests: this.calculateConcurrency(requests)
        };
        
        // Calculate averages
        metrics.avgDuration = metrics.totalDuration / requests.length;
        metrics.avgTTFB = requests.reduce((sum, r) => sum + r.timing.ttfb, 0) / requests.length;
        metrics.avgDownloadTime = requests.reduce((sum, r) => sum + r.timing.download, 0) / requests.length;
        
        this.results[version].metrics = metrics;
    }
    
    // Calculate request concurrency
    calculateConcurrency(requests) {
        if (requests.length === 0) return 0;
        
        const timeline = [];
        requests.forEach(req => {
            timeline.push({ time: req.startTime, type: 'start' });
            timeline.push({ time: req.startTime + req.duration, type: 'end' });
        });
        
        timeline.sort((a, b) => a.time - b.time);
        
        let current = 0;
        let max = 0;
        
        timeline.forEach(event => {
            if (event.type === 'start') {
                current++;
                max = Math.max(max, current);
            } else {
                current--;
            }
        });
        
        return max;
    }
    
    // Generate comparison report
    generateComparison() {
        const comparison = {
            summary: {},
            detailed: this.results,
            advantages: {}
        };
        
        // Compare HTTP/2 vs HTTP/1.1
        if (!this.results.http2.metrics.noData && !this.results.http1.metrics.noData) {
            const improvement = {
                duration: ((this.results.http1.metrics.avgDuration - 
                           this.results.http2.metrics.avgDuration) / 
                           this.results.http1.metrics.avgDuration * 100).toFixed(2),
                ttfb: ((this.results.http1.metrics.avgTTFB - 
                        this.results.http2.metrics.avgTTFB) / 
                        this.results.http1.metrics.avgTTFB * 100).toFixed(2),
                concurrency: this.results.http2.metrics.concurrentRequests - 
                            this.results.http1.metrics.concurrentRequests
            };
            
            comparison.advantages.http2 = {
                performanceGain: `${improvement.duration}% faster`,
                ttfbImprovement: `${improvement.ttfb}% lower TTFB`,
                concurrencyGain: `+${improvement.concurrency} concurrent requests`
            };
        }
        
        // Compare HTTP/3 vs HTTP/2
        if (!this.results.http3.metrics.noData && !this.results.http2.metrics.noData) {
            const improvement = {
                duration: ((this.results.http2.metrics.avgDuration - 
                           this.results.http3.metrics.avgDuration) / 
                           this.results.http2.metrics.avgDuration * 100).toFixed(2),
                ttfb: ((this.results.http2.metrics.avgTTFB - 
                        this.results.http3.metrics.avgTTFB) / 
                        this.results.http2.metrics.avgTTFB * 100).toFixed(2)
            };
            
            comparison.advantages.http3 = {
                performanceGain: `${improvement.duration}% faster than HTTP/2`,
                ttfbImprovement: `${improvement.ttfb}% lower TTFB`,
                additionalBenefits: ['No head-of-line blocking', '0-RTT connections', 'Connection migration']
            };
        }
        
        return comparison;
    }
}

// Run comparison
const comparison = new HTTPPerformanceComparison();
console.log(comparison.analyzePage());

HTTP/2 Optimization Analyzer

Analyze HTTP/2 optimization opportunities:

// HTTP/2 Optimization Analyzer
const HTTP2Optimizer = {
    // Analyze current HTTP/2 usage
    analyzeHTTP2Usage() {
        const analysis = {
            opportunities: [],
            issues: [],
            score: 100,
            recommendations: []
        };
        
        const resources = performance.getEntriesByType('resource');
        
        // Group resources by domain
        const domainResources = {};
        resources.forEach(resource => {
            const domain = new URL(resource.name).hostname;
            if (!domainResources[domain]) {
                domainResources[domain] = {
                    resources: [],
                    protocols: new Set(),
                    totalSize: 0,
                    totalRequests: 0
                };
            }
            
            domainResources[domain].resources.push(resource);
            domainResources[domain].protocols.add(resource.nextHopProtocol);
            domainResources[domain].totalSize += resource.transferSize || 0;
            domainResources[domain].totalRequests++;
        });
        
        // Analyze each domain
        Object.entries(domainResources).forEach(([domain, data]) => {
            // Check for HTTP/1.1 domains with many requests
            const protocols = Array.from(data.protocols);
            const isHTTP1 = protocols.some(p => p?.includes('http/1'));
            
            if (isHTTP1 && data.totalRequests > 6) {
                analysis.issues.push({
                    type: 'http1-bottleneck',
                    domain,
                    impact: 'high',
                    details: `${data.totalRequests} requests over HTTP/1.1 (max 6 concurrent)`,
                    recommendation: 'Upgrade to HTTP/2 or reduce request count'
                });
                analysis.score -= 15;
            }
            
            // Check for domain sharding (anti-pattern in HTTP/2)
            const baseDomain = domain.split('.').slice(-2).join('.');
            const subdomains = Object.keys(domainResources).filter(d => 
                d.endsWith(baseDomain) && d !== domain
            );
            
            if (subdomains.length > 2) {
                analysis.issues.push({
                    type: 'domain-sharding',
                    domain: baseDomain,
                    impact: 'medium',
                    details: 'Domain sharding detected - anti-pattern for HTTP/2',
                    recommendation: 'Consolidate resources to fewer domains with HTTP/2'
                });
                analysis.score -= 10;
            }
        });
        
        // Check for optimization opportunities
        this.checkServerPush(analysis);
        this.checkResourceHints(analysis);
        this.checkConnectionCoalescing(analysis, domainResources);
        
        // Generate recommendations
        if (analysis.score < 80) {
            analysis.recommendations.push(
                'Consider implementing HTTP/2 Push for critical resources',
                'Use resource hints (preconnect, dns-prefetch) for third-party domains',
                'Consolidate resources to minimize connection overhead'
            );
        }
        
        return analysis;
    },
    
    // Check for server push opportunities
    checkServerPush(analysis) {
        const criticalResources = performance.getEntriesByType('resource')
            .filter(r => {
                const isCritical = r.initiatorType === 'link' || 
                                 r.initiatorType === 'css' ||
                                 (r.initiatorType === 'script' && r.startTime < 1000);
                return isCritical && r.transferSize > 1024; // > 1KB
            });
        
        if (criticalResources.length > 0) {
            analysis.opportunities.push({
                type: 'server-push',
                resources: criticalResources.map(r => ({
                    url: r.name,
                    size: r.transferSize,
                    type: r.initiatorType
                })),
                benefit: 'Eliminate round trips for critical resources',
                implementation: 'Use Link header with rel=preload or HTTP/2 Push'
            });
        }
    },
    
    // Check for resource hints
    checkResourceHints(analysis) {
        const links = document.querySelectorAll('link[rel]');
        const hints = {
            preconnect: 0,
            dnsPrefetch: 0,
            prefetch: 0,
            preload: 0
        };
        
        links.forEach(link => {
            const rel = link.getAttribute('rel');
            if (hints.hasOwnProperty(rel)) {
                hints[rel]++;
            }
        });
        
        // Check third-party domains without preconnect
        const thirdPartyDomains = new Set();
        performance.getEntriesByType('resource').forEach(resource => {
            const domain = new URL(resource.name).hostname;
            if (domain !== window.location.hostname) {
                thirdPartyDomains.add(domain);
            }
        });
        
        const missingPreconnects = Array.from(thirdPartyDomains).filter(domain => {
            return !Array.from(links).some(link => 
                link.getAttribute('rel') === 'preconnect' && 
                link.getAttribute('href')?.includes(domain)
            );
        });
        
        if (missingPreconnects.length > 0) {
            analysis.opportunities.push({
                type: 'resource-hints',
                domains: missingPreconnects,
                benefit: 'Reduce connection setup time',
                implementation: 'Add <link rel="preconnect"> for third-party domains'
            });
        }
    },
    
    // Check for connection coalescing opportunities
    checkConnectionCoalescing(analysis, domainResources) {
        const relatedDomains = {};
        
        Object.keys(domainResources).forEach(domain => {
            const baseDomain = domain.split('.').slice(-2).join('.');
            if (!relatedDomains[baseDomain]) {
                relatedDomains[baseDomain] = [];
            }
            relatedDomains[baseDomain].push(domain);
        });
        
        Object.entries(relatedDomains).forEach(([base, domains]) => {
            if (domains.length > 1) {
                const http2Domains = domains.filter(d => 
                    Array.from(domainResources[d].protocols).some(p => p?.includes('h2'))
                );
                
                if (http2Domains.length > 1) {
                    analysis.opportunities.push({
                        type: 'connection-coalescing',
                        domains: http2Domains,
                        benefit: 'Reuse single HTTP/2 connection for multiple domains',
                        implementation: 'Ensure same IP and valid certificate for all domains'
                    });
                }
            }
        });
    }
};

HTTP/3 Readiness Checker

Check if your site is ready for HTTP/3:

// HTTP/3 Readiness Checker
const HTTP3Readiness = {
    async checkReadiness(url = window.location.origin) {
        const readiness = {
            score: 0,
            requirements: {
                https: false,
                http2: false,
                altSvc: false,
                udp443: 'unknown',
                quicSupport: false
            },
            browserSupport: this.checkBrowserSupport(),
            recommendations: []
        };
        
        try {
            // Check HTTPS
            const testUrl = new URL(url);
            readiness.requirements.https = testUrl.protocol === 'https:';
            if (readiness.requirements.https) readiness.score += 25;
            
            // Test endpoint
            const response = await fetch(url);
            
            // Check for HTTP/2
            const entries = performance.getEntriesByName(url);
            const lastEntry = entries[entries.length - 1];
            if (lastEntry?.nextHopProtocol?.includes('h2')) {
                readiness.requirements.http2 = true;
                readiness.score += 25;
            }
            
            // Check Alt-Svc header
            const altSvc = response.headers.get('alt-svc');
            if (altSvc) {
                readiness.requirements.altSvc = true;
                readiness.altSvcHeader = altSvc;
                
                if (altSvc.includes('h3')) {
                    readiness.requirements.quicSupport = true;
                    readiness.score += 25;
                }
            }
            
            // Browser support adds to score
            if (readiness.browserSupport.http3) {
                readiness.score += 25;
            }
            
        } catch (error) {
            readiness.error = error.message;
        }
        
        // Generate recommendations
        this.generateRecommendations(readiness);
        
        return readiness;
    },
    
    // Check browser HTTP/3 support
    checkBrowserSupport() {
        const support = {
            http3: false,
            quic: false,
            details: {}
        };
        
        // Check user agent for browser version
        const ua = navigator.userAgent;
        
        if (ua.includes('Chrome/')) {
            const version = parseInt(ua.match(/Chrome\/(\d+)/)[1]);
            support.details.chrome = version;
            support.http3 = version >= 87; // Chrome 87+ supports HTTP/3
        } else if (ua.includes('Firefox/')) {
            const version = parseInt(ua.match(/Firefox\/(\d+)/)[1]);
            support.details.firefox = version;
            support.http3 = version >= 88; // Firefox 88+ with flag
        } else if (ua.includes('Safari/')) {
            const version = parseInt(ua.match(/Version\/(\d+)/)?.[1] || 0);
            support.details.safari = version;
            support.http3 = version >= 14; // Safari 14+ experimental
        }
        
        // Check for QUIC indicators
        if (performance.getEntriesByType('resource').some(r => 
            r.nextHopProtocol?.includes('quic') || r.nextHopProtocol?.includes('h3')
        )) {
            support.quic = true;
            support.http3 = true;
        }
        
        return support;
    },
    
    // Generate HTTP/3 recommendations
    generateRecommendations(readiness) {
        if (!readiness.requirements.https) {
            readiness.recommendations.push({
                priority: 'critical',
                action: 'Enable HTTPS',
                reason: 'HTTP/3 requires secure connections'
            });
        }
        
        if (!readiness.requirements.http2) {
            readiness.recommendations.push({
                priority: 'high',
                action: 'Upgrade to HTTP/2 first',
                reason: 'HTTP/2 is a stepping stone to HTTP/3'
            });
        }
        
        if (!readiness.requirements.altSvc) {
            readiness.recommendations.push({
                priority: 'medium',
                action: 'Configure Alt-Svc header',
                reason: 'Advertises HTTP/3 support to clients',
                example: 'Alt-Svc: h3=":443"; ma=86400'
            });
        }
        
        if (!readiness.browserSupport.http3) {
            readiness.recommendations.push({
                priority: 'info',
                action: 'Update browser',
                reason: 'Your browser may not support HTTP/3'
            });
        }
        
        if (readiness.score === 100) {
            readiness.recommendations.push({
                priority: 'success',
                action: 'HTTP/3 Ready!',
                reason: 'Your site appears ready for HTTP/3'
            });
        }
    }
};

// Check HTTP/3 readiness
HTTP3Readiness.checkReadiness().then(console.log);

Protocol Performance Monitor

Real-time monitoring of protocol performance:

// Real-time Protocol Performance Monitor
class ProtocolPerformanceMonitor {
    constructor() {
        this.metrics = {
            byProtocol: {},
            timeline: [],
            aggregated: {}
        };
        this.observer = null;
    }
    
    // Start monitoring
    start() {
        // Use PerformanceObserver for real-time monitoring
        this.observer = new PerformanceObserver((list) => {
            for (const entry of list.getEntries()) {
                this.processEntry(entry);
            }
        });
        
        this.observer.observe({ entryTypes: ['resource', 'navigation'] });
        
        // Process existing entries
        performance.getEntriesByType('resource').forEach(entry => {
            this.processEntry(entry);
        });
        
        console.log('Protocol performance monitoring started');
    }
    
    // Process performance entry
    processEntry(entry) {
        const protocol = entry.nextHopProtocol || 'unknown';
        const protocolCategory = this.categorizeProtocol(protocol);
        
        if (!this.metrics.byProtocol[protocolCategory]) {
            this.metrics.byProtocol[protocolCategory] = {
                requests: 0,
                totalDuration: 0,
                totalSize: 0,
                timings: {
                    dns: 0,
                    tcp: 0,
                    ssl: 0,
                    ttfb: 0,
                    download: 0
                }
            };
        }
        
        const metrics = this.metrics.byProtocol[protocolCategory];
        metrics.requests++;
        metrics.totalDuration += entry.duration;
        metrics.totalSize += entry.transferSize || 0;
        
        // Add timings
        metrics.timings.dns += entry.domainLookupEnd - entry.domainLookupStart;
        metrics.timings.tcp += entry.connectEnd - entry.connectStart;
        if (entry.secureConnectionStart > 0) {
            metrics.timings.ssl += entry.connectEnd - entry.secureConnectionStart;
        }
        metrics.timings.ttfb += entry.responseStart - entry.requestStart;
        metrics.timings.download += entry.responseEnd - entry.responseStart;
        
        // Add to timeline
        this.metrics.timeline.push({
            timestamp: performance.now(),
            protocol: protocolCategory,
            duration: entry.duration,
            size: entry.transferSize
        });
        
        // Keep timeline reasonable size
        if (this.metrics.timeline.length > 1000) {
            this.metrics.timeline.shift();
        }
    }
    
    // Categorize protocol
    categorizeProtocol(protocol) {
        if (protocol.includes('h3') || protocol.includes('quic')) return 'HTTP/3';
        if (protocol.includes('h2')) return 'HTTP/2';
        if (protocol.includes('http/1')) return 'HTTP/1.1';
        return 'Unknown';
    }
    
    // Get current metrics
    getMetrics() {
        const report = {
            protocols: {},
            comparison: {},
            trends: {}
        };
        
        // Calculate averages and percentages
        let totalRequests = 0;
        Object.entries(this.metrics.byProtocol).forEach(([protocol, data]) => {
            totalRequests += data.requests;
            
            report.protocols[protocol] = {
                requests: data.requests,
                avgDuration: data.requests > 0 ? data.totalDuration / data.requests : 0,
                avgSize: data.requests > 0 ? data.totalSize / data.requests : 0,
                avgTimings: {}
            };
            
            // Calculate average timings
            Object.entries(data.timings).forEach(([phase, time]) => {
                report.protocols[protocol].avgTimings[phase] = 
                    data.requests > 0 ? time / data.requests : 0;
            });
        });
        
        // Calculate percentages
        Object.keys(report.protocols).forEach(protocol => {
            report.protocols[protocol].percentage = 
                (report.protocols[protocol].requests / totalRequests * 100).toFixed(2) + '%';
        });
        
        // Generate comparison
        if (report.protocols['HTTP/2'] && report.protocols['HTTP/1.1']) {
            const h2 = report.protocols['HTTP/2'];
            const h1 = report.protocols['HTTP/1.1'];
            
            report.comparison['HTTP/2 vs HTTP/1.1'] = {
                speedImprovement: ((h1.avgDuration - h2.avgDuration) / h1.avgDuration * 100).toFixed(2) + '%',
                ttfbImprovement: ((h1.avgTimings.ttfb - h2.avgTimings.ttfb) / h1.avgTimings.ttfb * 100).toFixed(2) + '%'
            };
        }
        
        if (report.protocols['HTTP/3'] && report.protocols['HTTP/2']) {
            const h3 = report.protocols['HTTP/3'];
            const h2 = report.protocols['HTTP/2'];
            
            report.comparison['HTTP/3 vs HTTP/2'] = {
                speedImprovement: ((h2.avgDuration - h3.avgDuration) / h2.avgDuration * 100).toFixed(2) + '%',
                ttfbImprovement: ((h2.avgTimings.ttfb - h3.avgTimings.ttfb) / h2.avgTimings.ttfb * 100).toFixed(2) + '%'
            };
        }
        
        return report;
    }
    
    // Stop monitoring
    stop() {
        if (this.observer) {
            this.observer.disconnect();
            console.log('Protocol performance monitoring stopped');
        }
    }
}

// Start monitoring
const monitor = new ProtocolPerformanceMonitor();
monitor.start();

// Check metrics after page loads
setTimeout(() => {
    console.log(monitor.getMetrics());
}, 5000);

Migration Guide Generator

Generate HTTP/2 and HTTP/3 migration guides:

// HTTP Protocol Migration Guide Generator
const MigrationGuide = {
    // Generate migration recommendations
    generateMigrationPlan(currentAnalysis) {
        const plan = {
            currentState: this.assessCurrentState(currentAnalysis),
            migrationPath: [],
            estimatedImpact: {},
            implementation: {}
        };
        
        // Determine migration path
        if (!plan.currentState.hasHTTPS) {
            plan.migrationPath.push('Enable HTTPS');
        }
        
        if (!plan.currentState.hasHTTP2) {
            plan.migrationPath.push('Migrate to HTTP/2');
        }
        
        if (plan.currentState.hasHTTP2 && !plan.currentState.hasHTTP3) {
            plan.migrationPath.push('Implement HTTP/3');
        }
        
        // Generate implementation details
        this.generateImplementationGuide(plan);
        
        // Estimate performance impact
        this.estimatePerformanceImpact(plan);
        
        return plan;
    },
    
    // Assess current state
    assessCurrentState(analysis) {
        return {
            hasHTTPS: window.location.protocol === 'https:',
            hasHTTP2: Object.keys(analysis.protocols || {}).includes('HTTP/2'),
            hasHTTP3: Object.keys(analysis.protocols || {}).includes('HTTP/3'),
            currentProtocols: Object.keys(analysis.protocols || {})
        };
    },
    
    // Generate implementation guide
    generateImplementationGuide(plan) {
        // HTTP/2 implementation
        plan.implementation.http2 = {
            nginx: `
# Enable HTTP/2 in Nginx
server {
    listen 443 ssl http2;
    ssl_certificate /path/to/certificate.crt;
    ssl_certificate_key /path/to/private.key;
    
    # HTTP/2 optimization
    http2_push_preload on;
    http2_max_field_size 16k;
    http2_max_header_size 32k;
}`,
            apache: `
# Enable HTTP/2 in Apache
# First enable module: a2enmod http2
<VirtualHost *:443>
    Protocols h2 http/1.1
    SSLEngine on
    SSLCertificateFile /path/to/certificate.crt
    SSLCertificateKeyFile /path/to/private.key
</VirtualHost>`,
            nodejs: `
// Enable HTTP/2 in Node.js
const http2 = require('http2');
const fs = require('fs');

const server = http2.createSecureServer({
    key: fs.readFileSync('private.key'),
    cert: fs.readFileSync('certificate.crt')
});

server.on('stream', (stream, headers) => {
    stream.respond({
        'content-type': 'text/html',
        ':status': 200
    });
    stream.end('<h1>Hello HTTP/2</h1>');
});

server.listen(443);`
        };
        
        // HTTP/3 implementation
        plan.implementation.http3 = {
            nginx: `
# Enable HTTP/3 in Nginx (requires nginx-quic)
server {
    listen 443 ssl http2;
    listen 443 quic reuseport;
    
    ssl_certificate /path/to/certificate.crt;
    ssl_certificate_key /path/to/private.key;
    
    # Enable QUIC and HTTP/3
    ssl_protocols TLSv1.3;
    add_header Alt-Svc 'h3=":443"; ma=86400';
    
    # QUIC parameters
    quic_retry on;
    quic_gso on;
}`,
            cloudflare: `
# Enable HTTP/3 via Cloudflare
1. Log in to Cloudflare dashboard
2. Go to Network tab
3. Enable "HTTP/3 (with QUIC)"
4. Cloudflare automatically handles HTTP/3 negotiation`,
            cdn: {
                cloudflare: 'Automatic HTTP/3 support',
                fastly: 'HTTP/3 available on enterprise plans',
                cloudfront: 'HTTP/3 support in preview'
            }
        };
    },
    
    // Estimate performance impact
    estimatePerformanceImpact(plan) {
        const impacts = {
            http2: {
                latencyReduction: '15-30%',
                throughputIncrease: '20-40%',
                benefits: [
                    'Multiplexing eliminates head-of-line blocking',
                    'Header compression reduces overhead',
                    'Server push for critical resources',
                    'Single connection per origin'
                ]
            },
            http3: {
                latencyReduction: '20-40%',
                throughputIncrease: '10-25%',
                benefits: [
                    '0-RTT connection establishment',
                    'Connection migration (mobile)',
                    'Improved loss recovery',
                    'No TCP head-of-line blocking'
                ]
            }
        };
        
        plan.estimatedImpact = impacts;
    }
};

Best Practices for HTTP/2 and HTTP/3

  1. Consolidate Resources: Reduce domain sharding, HTTP/2 handles multiplexing
  2. Implement Server Push Carefully: Only for critical resources
  3. Use Resource Hints: Preconnect for third-party domains
  4. Optimize for Single Connection: Leverage HTTP/2 multiplexing
  5. Enable HPACK Compression: Reduce header overhead
  6. Prepare for HTTP/3: Ensure QUIC/UDP is not blocked
  7. Monitor Protocol Usage: Track adoption and performance
  8. Test Fallback Behavior: Ensure graceful degradation
  9. Keep Certificates Updated: Required for HTTPS/HTTP2/HTTP3
  10. Use CDN with HTTP/3: Easier adoption path

Common Issues and Solutions

  • HTTP/2 Not Working: Check SSL/TLS configuration, ensure ALPN support
  • Poor HTTP/2 Performance: Avoid domain sharding, check server configuration
  • HTTP/3 Connection Failures: UDP port 443 might be blocked
  • Protocol Downgrade: Network middleboxes interfering
  • Server Push Issues: Can cause cache problems if misconfigured
  • High Memory Usage: HTTP/2 connection state overhead
  • QUIC Blocked: Corporate firewalls often block UDP
  • Certificate Issues: HTTP/3 requires valid certificates
  • Browser Compatibility: Not all browsers support HTTP/3
  • Debugging Difficulties: HTTP/3 tools still maturing

Remember: The web is evolving rapidly. HTTP/2 is now standard, and HTTP/3 is the future. Stay ahead by understanding these protocols, implementing them correctly, and monitoring their performance impact on your applications.