Come rilevare la velocità di Internet in JavaScript?


214

Come posso creare una pagina JavaScript che rileverà la velocità di Internet dell'utente e la mostrerà sulla pagina? Qualcosa come "la tua velocità di internet è ?? / ?? Kb / s " .


1
@Jakub, @Ankit: le persone possono usare Flash per questo, ma non è necessario . Nessun motivo per cui non puoi farlo con JavaScript.
TJ Crowder,

Questo è ciò di cui hai bisogno: speedof.me/api.html
advncd

Risposte:


288

È possibile in una certa misura, ma non sarà molto preciso, l'idea è caricare l'immagine con una dimensione del file nota, quindi nel suo onloadevento misurare quanto tempo è trascorso prima che l'evento sia stato attivato e dividere questa volta per la dimensione del file di immagine.

Qui puoi trovare un esempio: calcola la velocità usando JavaScript

Caso di prova applicando la correzione suggerita lì:

//JUST AN EXAMPLE, PLEASE USE YOUR OWN PICTURE!
var imageAddr = "http://www.kenrockwell.com/contax/images/g2/examples/31120037-5mb.jpg"; 
var downloadSize = 4995374; //bytes

function ShowProgressMessage(msg) {
    if (console) {
        if (typeof msg == "string") {
            console.log(msg);
        } else {
            for (var i = 0; i < msg.length; i++) {
                console.log(msg[i]);
            }
        }
    }
    
    var oProgress = document.getElementById("progress");
    if (oProgress) {
        var actualHTML = (typeof msg == "string") ? msg : msg.join("<br />");
        oProgress.innerHTML = actualHTML;
    }
}

function InitiateSpeedDetection() {
    ShowProgressMessage("Loading the image, please wait...");
    window.setTimeout(MeasureConnectionSpeed, 1);
};    

if (window.addEventListener) {
    window.addEventListener('load', InitiateSpeedDetection, false);
} else if (window.attachEvent) {
    window.attachEvent('onload', InitiateSpeedDetection);
}

function MeasureConnectionSpeed() {
    var startTime, endTime;
    var download = new Image();
    download.onload = function () {
        endTime = (new Date()).getTime();
        showResults();
    }
    
    download.onerror = function (err, msg) {
        ShowProgressMessage("Invalid image, or error downloading");
    }
    
    startTime = (new Date()).getTime();
    var cacheBuster = "?nnn=" + startTime;
    download.src = imageAddr + cacheBuster;
    
    function showResults() {
        var duration = (endTime - startTime) / 1000;
        var bitsLoaded = downloadSize * 8;
        var speedBps = (bitsLoaded / duration).toFixed(2);
        var speedKbps = (speedBps / 1024).toFixed(2);
        var speedMbps = (speedKbps / 1024).toFixed(2);
        ShowProgressMessage([
            "Your connection speed is:", 
            speedBps + " bps", 
            speedKbps + " kbps", 
            speedMbps + " Mbps"
        ]);
    }
}
<h1 id="progress">JavaScript is turned off, or your browser is realllllly slow</h1>

Il rapido confronto con il servizio di test della velocità "reale" ha mostrato una piccola differenza di 0,12 Mbps quando si utilizza un'immagine di grandi dimensioni.

Per garantire l'integrità del test, puoi eseguire il codice con la limitazione dello strumento di sviluppo di Chrome abilitata e quindi vedere se il risultato corrisponde alla limitazione. (il credito va all'utente284130 :))

Cose importanti da tenere a mente:

  1. L'immagine utilizzata deve essere adeguatamente ottimizzata e compressa. In caso contrario, la compressione predefinita per le connessioni da parte del server Web potrebbe mostrare una velocità maggiore di quella attuale. Un'altra opzione sta usando un formato di file non comprimibile, ad esempio jpg. (grazie Rauli Rajande per averlo segnalato e Fluxine per avermelo ricordato )

  2. Il meccanismo di busting della cache descritto sopra potrebbe non funzionare con alcuni server CDN, che possono essere configurati per ignorare i parametri della stringa di query, quindi impostare meglio le intestazioni di controllo della cache sull'immagine stessa. (grazie orcaman per averlo segnalato ) )


8
Accertarsi che l'immagine di prova sia adeguatamente ottimizzata e compressa. In caso contrario, la compressione predefinita sulle connessioni da parte del server web potrebbe mostrare una velocità maggiore di quanto non sia in realtà.
Rauli Rajande,

3
Ho trovato un piccolo trucco per assicurarmi che la tua immagine fosse adatta al test: esegui il codice con la limitazione dello strumento di sviluppo di Chrome abilitata e vedi se il risultato corrisponde alla limitazione. Spero che questo possa aiutare qualcuno.
user284130,

3
unirsi a Rauli Rajande: meglio usare un file non comprimibile (o quasi), oppure i moduli di compressione del server web possono ridurlo significativamente, invalidando la misura. Un'immagine jpeg sarebbe una buona scelta.
Fluxine,

1
Per coloro che hanno usato con successo questo codice Javascript, inizialmente non hai ricevuto chiamate andando a "download.onload"? Questo è esattamente ciò che sto vivendo e sto ancora cercando di scoprire perché.

2
L'immagine più piccola di @Dilip significa test meno accurati, è grande apposta. :)
Shadow Wizard is Ear For You

78

Bene, questo è il 2017, quindi ora hai l'API delle informazioni di rete (anche se con un supporto limitato tra i browser a partire da ora) per ottenere una sorta di stima della velocità di downlink:

navigator.connection.downlink

Questa è una stima della larghezza di banda effettiva in Mbits al secondo. Il browser effettua questa stima dal throughput del livello applicazione osservato di recente attraverso connessioni attive di recente. Inutile dire che il più grande vantaggio di questo approccio è che non è necessario scaricare alcun contenuto solo per il calcolo della larghezza di banda / velocità.

Puoi vedere questo e un paio di altri attributi correlati qui

A causa del supporto limitato e delle diverse implementazioni tra i browser (a partire da novembre 2017), consigliamo vivamente di leggere questo in dettaglio


18
È molto rosso in Can I Use!
Francisco Presencia,

2
Non ottengo numeri superiori a 10 MB usando questo. C'è un limite?
Tobi

@Tobi Anche io non riesco a superare i 10 MB, dovrei essere più simile a 100 MB
camjocotem il

Che cos'è esattamente il downlink? È la velocità di download o qualcosa del genere?
Gacat,

@Tobi Neanch'io, se la velocità è superiore a 10Mb continuo a leggere 10
Aramil

21

Come ho delineato in questa altra risposta qui su StackOverflow , puoi farlo tempificando il download di file di varie dimensioni (inizia piccolo, accelera se la connessione sembra consentirlo), assicurandoti attraverso le intestazioni della cache e tale che il file sia davvero viene letto dal server remoto e non viene recuperato dalla cache. Questo non richiede necessariamente che tu abbia un tuo server (i file potrebbero provenire da S3 o simili), ma avrai bisogno di un posto da cui ottenere i file per testare la velocità di connessione.

Detto questo, i test della larghezza di banda point-in-time sono notoriamente inaffidabili, poiché sono influenzati da altri elementi scaricati in altre finestre, dalla velocità del server, dai collegamenti lungo il percorso, ecc. Ecc. Ma puoi avere un'idea approssimativa usando questo tipo di tecnica.


1
@Jakub: dovresti avere un posto dove caricare, ma non c'è motivo per cui non puoi usare la stessa tecnica per quello. È possibile utilizzare i dati generati al volo o, naturalmente, è possibile riutilizzare alcuni dei dati scaricati per il test di download.
TJ Crowder,

Quindi come fai a sapere quando è stato completato il caricamento?
Jakub Hampl,

2
@Jakub: uno dei vari modi. Se invii un modulo a un nascosto iframe, ad esempio, esegui il polling del iframecookie o di un cookie per il completamento. Se usi un XMLHttpRequestoggetto per scrivere il post, c'è un callback per il completamento.
TJ Crowder,

18

Avevo bisogno di un modo rapido per determinare se la velocità di connessione dell'utente era abbastanza veloce da abilitare / disabilitare alcune funzionalità in un sito su cui sto lavorando, ho realizzato questo piccolo script che calcola la media del tempo necessario per scaricare una (piccola) immagine a molte volte, sta funzionando abbastanza accuratamente nei miei test, essendo in grado di distinguere chiaramente tra 3G o Wi-Fi, ad esempio, forse qualcuno può creare una versione più elegante o persino un plugin jQuery.

var arrTimes = [];
var i = 0; // start
var timesToTest = 5;
var tThreshold = 150; //ms
var testImage = "http://www.google.com/images/phd/px.gif"; // small image in your server
var dummyImage = new Image();
var isConnectedFast = false;

testLatency(function(avg){
  isConnectedFast = (avg <= tThreshold);
  /** output */
  document.body.appendChild(
    document.createTextNode("Time: " + (avg.toFixed(2)) + "ms - isConnectedFast? " + isConnectedFast)
  );
});

/** test and average time took to download image from server, called recursively timesToTest times */
function testLatency(cb) {
  var tStart = new Date().getTime();
  if (i<timesToTest-1) {
    dummyImage.src = testImage + '?t=' + tStart;
    dummyImage.onload = function() {
      var tEnd = new Date().getTime();
      var tTimeTook = tEnd-tStart;
      arrTimes[i] = tTimeTook;
      testLatency(cb);
      i++;
    };
  } else {
    /** calculate average of array items then callback */
    var sum = arrTimes.reduce(function(a, b) { return a + b; });
    var avg = sum / arrTimes.length;
    cb(avg);
  }
}


1
La risposta più affidabile, nel mio caso.
Abdalla Arbab,

1
che dire del test di caricamento?
Gumuruh,

9

Il trucco dell'immagine è bello ma nei miei test si stava caricando prima che alcune chiamate ajax volessi essere complete.

La soluzione corretta nel 2017 è quella di utilizzare un lavoratore ( http://caniuse.com/#feat=webworkers ).

Il lavoratore sarà simile a:

/**
 * This function performs a synchronous request
 * and returns an object contain informations about the download
 * time and size
 */
function measure(filename) {
  var xhr = new XMLHttpRequest();
  var measure = {};
  xhr.open("GET", filename + '?' + (new Date()).getTime(), false);
  measure.start = (new Date()).getTime();
  xhr.send(null);
  measure.end = (new Date()).getTime();
  measure.len = parseInt(xhr.getResponseHeader('Content-Length') || 0);
  measure.delta = measure.end - measure.start;
  return measure;
}

/**
 * Requires that we pass a base url to the worker
 * The worker will measure the download time needed to get
 * a ~0KB and a 100KB.
 * It will return a string that serializes this informations as
 * pipe separated values
 */
onmessage = function(e) {
  measure0 = measure(e.data.base_url + '/test/0.bz2');
  measure100 = measure(e.data.base_url + '/test/100K.bz2');
  postMessage(
    measure0.delta + '|' +
    measure0.len + '|' +
    measure100.delta + '|' +
    measure100.len
  );
};

Il file js che invocherà il lavoratore:

var base_url = PORTAL_URL + '/++plone++experimental.bwtools';
if (typeof(Worker) === 'undefined') {
  return; // unsupported
}
w = new Worker(base_url + "/scripts/worker.js");
w.postMessage({
  base_url: base_url
});
w.onmessage = function(event) {
  if (event.data) {
    set_cookie(event.data);
  }
};

Codice preso da un pacchetto Plone che ho scritto:


5

È meglio usare le immagini per testare la velocità. Ma se hai a che fare con i file zip, il codice qui sotto funziona.

var fileURL = "your/url/here/testfile.zip";

var request = new XMLHttpRequest();
var avoidCache = "?avoidcache=" + (new Date()).getTime();;
request.open('GET', fileURL + avoidCache, true);
request.responseType = "application/zip";
var startTime = (new Date()).getTime();
var endTime = startTime;
request.onreadystatechange = function () {
    if (request.readyState == 2)
    {
        //ready state 2 is when the request is sent
        startTime = (new Date().getTime());
    }
    if (request.readyState == 4)
    {
        endTime = (new Date()).getTime();
        var downloadSize = request.responseText.length;
        var time = (endTime - startTime) / 1000;
        var sizeInBits = downloadSize * 8;
        var speed = ((sizeInBits / time) / (1024 * 1024)).toFixed(2);
        console.log(downloadSize, time, speed);
    }
}

request.send();

Questo non funzionerà molto bene con file <10 MB. Dovrai eseguire risultati aggregati su più tentativi di download.


3
Mi piace molto la semplicità della risposta e l'ho adattata per il mio scopo: ho scambiato con window.performance.now per i timestamp, request.responseType = "blob" (i tipi MIME non sono validi), request.response.size per la dimensione del download e 1000000 per il calcolo della velocità (poiché Mbps dovrebbe essere in unità SI).
Rupert Rawnsley,


1

grazie alla risposta Punit S, per rilevare la variazione dinamica della velocità di connessione, è possibile utilizzare il seguente codice:

navigator.connection.onchange = function () {
 //do what you need to do ,on speed change event
 console.log('Connection Speed Changed');
}

2
purtroppo non supporta tutti i browser. caniuse.com/#search=netinfo
axelioo
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.