How to calculate download / upload internet speed in Angular

What is the internet speed?

Everyone want to download faster and faster, and also upload files even faster. But what does it mean? When you download or upload something, you and a server are communicating in a particular way.Both of you have an internet connection, but in most cases, your is slower than the server's connection. To understand this, simply follow this logic:

You are playing some video games with other thousands of user. Your (and the other player connection) can send and receive 20 units per second. The server can send up to 2 millions unit per second. In this way everyone is happy and is online. If the server could just send 20 units per second, everyone would've lagged, or even worst (Like package loss).

So, to answer what internet speed is, is the time that takes from a request sent to you, to travel to the server, have a response, and then turn it back to you. Of course if the server is down or has finished his units space to dedicate to you, your request would be delayed, but this is how the internet works.

When you download or stream a film, it happens the same thing: You are requesting new chunk every time you finished to download/stream a small part.

Let's talk about some number

Time is counted, in the internet, in milliseconds. If you just open a terminal and do a simple ping www.stackoverflow.com you will have something like that :

Reply from 151.101.1.69: bytes=32 time=36ms TTL=56
Reply from 151.101.1.69: bytes=32 time=36ms TTL=56
Reply from 151.101.1.69: bytes=32 time=36ms TTL=56
Reply from 151.101.1.69: bytes=32 time=36ms TTL=56

that time=36ms is the time passed between you sending the ping request, and the request backing to you.

In the end

I hope to have cleared everything, measuring time, in the web, is intended like this way:

- Start counting
- Send a request
- ... 
- Wait..
- ...
- Request turned back
- Stop Counting

** But my question is: Can I do it in angular?**

The answer is.. Kinda. Probably there are better ways to do that, but few months ago I wanted to do it as well, and I came up with that idea.

Let's assume we have a service that do a request :

export class MyService{
  constructor(
    private http: Http
  )

  public sendRequest(){
    return this.http.get(...something);
  }
}

Our main component will have the service injection and will count the times passed :

export class MyComponent{
  public timePassed: any;

  constructor(
    private service: MyService
  )

  ngOnInit(): void{
    const startingTime = new Date().getTime();

    this.service.sendRequest()
    .subscribe( res => {
         this.timePassed = ((new Date() - startingTime).getTime())/1000;
    });
  }
}

Now in your timePassed variable you will have the time that the request took. As I said, the time can change due to your connection being slow, or because the server's connection is slow.

You always have to think at internet speed like two people talking to each other. Always. It makes no sense otherwise to talk to speed if you can't relate yours to someone else speed.


If you want to use third party API, there are some dedicated speed test websites, which also provide API access. E.g:

  • https://myspeed.today
  • http://www.speedtest.net
  • https://speedof.me/api.html
  • Some more: https://duckduckgo.com/?q=free+speedtest+api

You can checkout related SO answers here.

OR

If you want to implement it yourself in Angular, you can checkout my repository. I did this sometime ago to test download speed: angular-speed-test.

I used Angular HttpClient progress events to track transfer of data and calculated speed based on that.

service code:

import { Injectable } from "@angular/core";
import { HttpClient, HttpRequest } from "@angular/common/http";

@Injectable({
  providedIn: "root"
})
export class FileDownloaderService {
  url: string = "some file path for download";

  constructor(private http: HttpClient) {}

  download() {
    const req = new HttpRequest("GET", this.url, {
      responseType: "blob",
      reportProgress: true
    });
    return this.http.request(req);
  }
}

component:

import { Component } from "@angular/core";
import { HttpClient, HttpEventType, HttpResponse } from "@angular/common/http";
import { FileDownloaderService } from "./file-downloader.service";

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent {
  constructor(
    private http: HttpClient,
    private downloader: FileDownloaderService
  ) {}

  percentDone: number;
  startTime: any;
  endTime: any;
  currTime: any;
  prevTime: any;
  speed: number = 0;
  bytesReceied: number = 0;
  oldbytes: number = 0;
  unit: string = "Mbps";

  download() {
    this.downloader.download().subscribe(event => {
      if (event.type === HttpEventType.DownloadProgress) {

        //tracking percent received and how much time has passed
        this.percentDone = Math.round((100 * event.loaded) / event.total);    
        this.currTime = new Date().getTime();

        //setting start time
        if (this.percentDone === 0) {
          this.startTime = new Date().getTime();
          this.prevTime = this.startTime;
        }

        //tracking how much data is received
        this.bytesReceied = event.loaded / 1000000;

        //calculating download speed per percent data received
        this.speed =
          (this.bytesReceied - this.oldbytes) /
          ((this.currTime - this.prevTime) / 1000);
        if (this.speed < 1) {
          this.unit = "Kbps";
          this.speed *= 1000;
        } else this.unit = "Mbps";

        //updating previous values
        this.prevTime = this.currTime;    
        this.oldbytes = this.bytesReceied;

        //calculating avg download speed
        if (this.percentDone === 100) {
          this.endTime = new Date().getTime();
          let duration = (this.endTime - this.startTime) / 1000;
          let mbps = event.total / duration / 1000000;
          if (mbps < 1) {
            this.speed = event.total / duration / 1000;
            this.unit = "Kbps";
          } else {
            this.speed = mbps;
            this.unit = "Mbps";
          }
        }

      }
      //download file
      else if (event instanceof HttpResponse) {
        var res: any = event.body;
        var url = window.URL.createObjectURL(res);
        var a = document.createElement("a");
        document.body.appendChild(a);
        a.setAttribute("style", "display: none");
        a.href = url;
        a.download = "SpeedTest_32MB.dat";
        a.click();
        window.URL.revokeObjectURL(url);
        a.remove();
        console.log("File is completely downloaded!");
      }
    });
  }
}

Demo


I think this is totally independent of Angular. Furthermore using a connection to a server seems to be the only way to perform the desired measurement. All speed test pages I know of are using very powerful, well-connected servers from which they receive packages of known sizes (or upload to them).

Tags:

Angular