javascript 55 lines · 7 steps

Estimating download speed with a sliding window

A DownloadTracker measures transfer rate over a recent time window to compute live speed and ETA.

Explained by highlit
1class DownloadTracker {
2 constructor(totalBytes, { windowMs = 3000 } = {}) {
3 this.totalBytes = totalBytes;
4 this.windowMs = windowMs;
5 this.transferred = 0;
6 this.samples = [];
7 }
8 
9 update(bytes) {
10 this.transferred += bytes;
11 const now = performance.now();
12 this.samples.push({ t: now, transferred: this.transferred });
13 const cutoff = now - this.windowMs;
14 while (this.samples.length > 1 && this.samples[0].t < cutoff) {
15 this.samples.shift();
16 }
17 }
18 
19 get speed() {
20 if (this.samples.length < 2) return 0;
21 const first = this.samples[0];
22 const last = this.samples[this.samples.length - 1];
23 const elapsed = (last.t - first.t) / 1000;
24 if (elapsed <= 0) return 0;
25 return (last.transferred - first.transferred) / elapsed;
26 }
27 
28 get eta() {
29 const speed = this.speed;
30 if (speed <= 0) return Infinity;
31 return (this.totalBytes - this.transferred) / speed;
32 }
33 
34 formatSpeed() {
35 let value = this.speed;
36 const units = ["B/s", "KB/s", "MB/s", "GB/s"];
37 let i = 0;
38 while (value >= 1024 && i < units.length - 1) {
39 value /= 1024;
40 i++;
41 }
42 return `${value.toFixed(value < 10 && i > 0 ? 1 : 0)} ${units[i]}`;
43 }
44 
45 formatEta() {
46 const seconds = this.eta;
47 if (!Number.isFinite(seconds)) return "--:--";
48 const s = Math.round(seconds);
49 const h = Math.floor(s / 3600);
50 const m = Math.floor((s % 3600) / 60);
51 const sec = s % 60;
52 const pad = (n) => String(n).padStart(2, "0");
53 return h > 0 ? `${h}:${pad(m)}:${pad(sec)}` : `${pad(m)}:${pad(sec)}`;
54 }
55}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Measuring rate over a recent time window smooths out bursts and stale readings better than a lifetime average.
  2. 2Getters let derived values like speed and ETA stay always-current without manual recomputation.
  3. 3Trimming old samples keeps memory bounded while preserving enough data to compute a meaningful slope.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Estimating download speed with a sliding window — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code