-
-
Notifications
You must be signed in to change notification settings - Fork 32.9k
Open
Labels
docIssues and PRs related to the documentations.Issues and PRs related to the documentations.good first issueIssues that are suitable for first-time contributors.Issues that are suitable for first-time contributors.
Description
Version
v22.18.0
Platform
Darwin MBP-14-Work.local 24.6.0 Darwin Kernel Version 24.6.0: Mon Jul 14 11:30:40 PDT 2025; root:xnu-11417.140.69~1/RELEASE_ARM64_T6041 arm64
Subsystem
No response
What steps will reproduce the bug?
Run the following performance test from the command line:
#!/usr/bin/env node
const { spawn } = require('child_process');
const fs = require('fs');
const path = require('path');
// Create test files
const withHttpCode = `
import { STATUS_CODES } from 'http';
console.log(Object.keys(STATUS_CODES).length);
const startTime = process.hrtime.bigint();
const endTime = process.hrtime.bigint();
console.log(Number(endTime - startTime) / 1000000); // Convert to milliseconds
`;
const withoutHttpCode = `
const { STATUS_CODES } = require('http');
console.log(Object.keys(STATUS_CODES).length);
const startTime = process.hrtime.bigint();
const endTime = process.hrtime.bigint();
console.log(Number(endTime - startTime) / 1000000); // Convert to milliseconds
`;
// Write test files
fs.writeFileSync('with-http.js', withHttpCode);
fs.writeFileSync('without-http.js', withoutHttpCode);
async function runBenchmark() {
const iterations = 100;
const withHttpTimes = [];
const withoutHttpTimes = [];
console.log(`Running benchmark with ${iterations} iterations...\n`);
// Benchmark with http import
console.log('Testing with http import...');
for (let i = 0; i < iterations; i++) {
const startTime = process.hrtime.bigint();
const child = spawn('node', ['with-http.js'], { stdio: 'pipe' });
await new Promise((resolve) => {
let output = '';
child.stdout.on('data', (data) => {
output += data.toString();
});
child.on('close', () => {
const endTime = process.hrtime.bigint();
const totalTime = Number(endTime - startTime) / 1000000; // Convert to milliseconds
withHttpTimes.push(totalTime);
resolve();
});
});
if (i % 10 === 0) process.stdout.write('.');
}
console.log(' Done!');
// Benchmark without http import
console.log('Testing without http import...');
for (let i = 0; i < iterations; i++) {
const startTime = process.hrtime.bigint();
const child = spawn('node', ['without-http.js'], { stdio: 'pipe' });
await new Promise((resolve) => {
let output = '';
child.stdout.on('data', (data) => {
output += data.toString();
});
child.on('close', () => {
const endTime = process.hrtime.bigint();
const totalTime = Number(endTime - startTime) / 1000000; // Convert to milliseconds
withoutHttpTimes.push(totalTime);
resolve();
});
});
if (i % 10 === 0) process.stdout.write('.');
}
console.log(' Done!\n');
// Calculate statistics
function calculateStats(times) {
const sorted = times.sort((a, b) => a - b);
const sum = times.reduce((a, b) => a + b, 0);
const avg = sum / times.length;
const median = sorted[Math.floor(sorted.length / 2)];
const min = Math.min(...times);
const max = Math.max(...times);
return { avg, median, min, max };
}
const withHttpStats = calculateStats(withHttpTimes);
const withoutHttpStats = calculateStats(withoutHttpTimes);
// Display results
console.log('='.repeat(60));
console.log('BENCHMARK RESULTS');
console.log('='.repeat(60));
console.log('\nWith HTTP import:');
console.log(` Average: ${withHttpStats.avg.toFixed(2)} ms`);
console.log(` Median: ${withHttpStats.median.toFixed(2)} ms`);
console.log(` Min: ${withHttpStats.min.toFixed(2)} ms`);
console.log(` Max: ${withHttpStats.max.toFixed(2)} ms`);
console.log('\nWithout HTTP import:');
console.log(` Average: ${withoutHttpStats.avg.toFixed(2)} ms`);
console.log(` Median: ${withoutHttpStats.median.toFixed(2)} ms`);
console.log(` Min: ${withoutHttpStats.min.toFixed(2)} ms`);
console.log(` Max: ${withoutHttpStats.max.toFixed(2)} ms`);
const avgDiff = withHttpStats.avg - withoutHttpStats.avg;
const medianDiff = withHttpStats.median - withoutHttpStats.median;
console.log('\nDifference (with HTTP - without HTTP):');
console.log(` Average: ${avgDiff.toFixed(2)} ms (${((avgDiff / withoutHttpStats.avg) * 100).toFixed(1)}%)`);
console.log(` Median: ${medianDiff.toFixed(2)} ms (${((medianDiff / withoutHttpStats.median) * 100).toFixed(1)}%)`);
console.log('\n' + '='.repeat(60));
// Cleanup
fs.unlinkSync('with-http.js');
fs.unlinkSync('without-http.js');
}
// Run the benchmark
runBenchmark().catch(console.error);
How often does it reproduce? Is there a required condition?
Always when I run the performance test.
What is the expected behavior? Why is that the expected behavior?
Importing a constant from http
should not be significantly slower when using import
vs require
.
What do you see instead?
Using import
is a lot slower:
Running benchmark with 100 iterations...
Testing with http import...
.......... Done!
Testing without http import...
.......... Done!
============================================================
BENCHMARK RESULTS
============================================================
With HTTP import:
Average: 26.88 ms
Median: 26.08 ms
Min: 25.19 ms
Max: 67.84 ms
Without HTTP import:
Average: 17.54 ms
Median: 17.44 ms
Min: 16.66 ms
Max: 21.56 ms
Difference (with HTTP - without HTTP):
Average: 9.33 ms (53.2%)
Median: 8.64 ms (49.5%)
============================================================
Additional information
Is it possible that the lazy undici method gets run when using import
?
Lines 118 to 124 in 5af0355
/** | |
* Lazy loads WebSocket, CloseEvent and MessageEvent classes from undici | |
* @returns {object} An object containing WebSocket, CloseEvent, and MessageEvent classes. | |
*/ | |
function lazyUndici() { | |
return undici ??= require('internal/deps/undici/undici'); | |
} |
Metadata
Metadata
Assignees
Labels
docIssues and PRs related to the documentations.Issues and PRs related to the documentations.good first issueIssues that are suitable for first-time contributors.Issues that are suitable for first-time contributors.