How to Calculate Axios Upload Speed Dynamically
Calculating real-time upload speed with Axios involves tracking the
number of bytes transferred over specific time intervals during the
upload process. By leveraging the onUploadProgress
configuration option in Axios, you can measure elapsed time alongside
the bytes loaded to calculate instantaneous throughput, rolling
averages, and remaining time dynamically in both browser and Node.js
environments.
Core Formula for Transfer Speed
Transfer speed is defined as data transferred divided by the time taken:
\[\text{Speed (Bytes/sec)} = \frac{\text{Bytes Transferred}}{\text{Time Elapsed (seconds)}}\]
To make this calculation dynamic rather than a static total average, you must measure the difference in bytes and time between consecutive progress events.
Implementation with Axios
Axios provides the onUploadProgress callback in its
request configuration. The event object contains loaded
(bytes transferred) and total (total file size in
bytes).
Here is a complete implementation using dynamic interval tracking:
import axios from 'axios';
async function uploadFileWithSpeedTracking(file, uploadUrl) {
const formData = new FormData();
formData.append('file', file);
let lastTime = performance.now();
let lastLoaded = 0;
const response = await axios.post(uploadUrl, formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
onUploadProgress: (progressEvent) => {
const currentTime = performance.now();
const timeElapsedInSeconds = (currentTime - lastTime) / 1000;
// Avoid division by zero on rapid consecutive events
if (timeElapsedInSeconds > 0) {
const bytesChunk = progressEvent.loaded - lastLoaded;
const currentSpeedBytesPerSec = bytesChunk / timeElapsedInSeconds;
// Calculate progress percentage
const percentCompleted = progressEvent.total
? Math.round((progressEvent.loaded * 100) / progressEvent.total)
: 0;
// Calculate Estimated Time Remaining (ETA)
const remainingBytes = progressEvent.total - progressEvent.loaded;
const etaSeconds = currentSpeedBytesPerSec > 0
? (remainingBytes / currentSpeedBytesPerSec).toFixed(1)
: 0;
console.log({
percent: `${percentCompleted}%`,
speed: formatSpeed(currentSpeedBytesPerSec),
eta: `${etaSeconds}s`,
});
// Update tracking references for the next event
lastTime = currentTime;
lastLoaded = progressEvent.loaded;
}
},
});
return response.data;
}
function formatSpeed(bytesPerSecond) {
if (bytesPerSecond >= 1024 * 1024) {
return `${(bytesPerSecond / (1024 * 1024)).toFixed(2)} MB/s`;
}
if (bytesPerSecond >= 1024) {
return `${(bytesPerSecond / 1024).toFixed(2)} KB/s`;
}
return `${Math.round(bytesPerSecond)} B/s`;
}Improving Accuracy with Moving Averages
Instantaneous measurements can fluctuate rapidly due to network jitter. Implementing an Exponential Moving Average (EMA) provides smoother UI updates:
let smoothedSpeed = 0;
const smoothingFactor = 0.2; // Adjust between 0.1 (smoother) and 0.9 (more responsive)
function updateSmoothedSpeed(instantaneousSpeed) {
if (smoothedSpeed === 0) {
smoothedSpeed = instantaneousSpeed;
} else {
smoothedSpeed = (instantaneousSpeed * smoothingFactor) + (smoothedSpeed * (1 - smoothingFactor));
}
return smoothedSpeed;
}Integrating this helper smooths out erratic changes when rendering upload speeds on a progress bar or status dashboard.