Wie erkenne ich die Internetgeschwindigkeit in JavaScript?

213

Wie kann ich eine JavaScript-Seite erstellen, die die Internetgeschwindigkeit des Benutzers erkennt und auf der Seite anzeigt? So etwas wie "Ihre Internetgeschwindigkeit ist ?? / ?? Kb / s ” .

Sharon Haim Pour
quelle
1
@Jakub, @Ankit: Menschen kann es verwenden , Blitz, aber Sie nicht brauchen , um. Kein Grund, warum Sie es nicht mit JavaScript machen können.
TJ Crowder
Dies ist, was Sie brauchen: speedof.me/api.html
advncd

Antworten:

287

Es ist bis zu einem gewissen Grad möglich, aber nicht wirklich genau. Die Idee ist, ein Bild mit einer bekannten Dateigröße zu laden und dann in seinem onloadEreignis zu messen, wie viel Zeit vergangen ist, bis dieses Ereignis ausgelöst wurde, und diese Zeit in die Bilddateigröße zu teilen.

Ein Beispiel finden Sie hier: Berechnen Sie die Geschwindigkeit mit Javascript

Testfall unter Anwendung des dort vorgeschlagenen Fixes:

//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>

Ein schneller Vergleich mit dem "echten" Geschwindigkeitstestdienst ergab einen kleinen Unterschied von 0,12 Mbit / s bei Verwendung des Gesamtbilds.

Um die Integrität des Tests sicherzustellen, können Sie den Code mit aktivierter Drosselung des Chrome Dev-Tools ausführen und dann prüfen, ob das Ergebnis der Einschränkung entspricht. (Gutschrift geht an user284130 :))

Wichtige Dinge zu beachten:

  1. Das verwendete Bild sollte ordnungsgemäß optimiert und komprimiert werden. Wenn dies nicht der Fall ist, zeigt die Standardkomprimierung bei Verbindungen durch den Webserver möglicherweise eine höhere Geschwindigkeit als sie tatsächlich ist. Eine andere Option ist die Verwendung eines nicht komprimierbaren Dateiformats, z. B. jpg. (Danke an Rauli Rajande für diesen Hinweis und Fluxine für die Erinnerung an mich )

  2. Der oben beschriebene Cache-Buster-Mechanismus funktioniert möglicherweise nicht mit einigen CDN-Servern, die so konfiguriert werden können, dass Abfragezeichenfolgenparameter ignoriert werden, wodurch die Cache-Steuerungsheader für das Image selbst besser festgelegt werden. (Dank orcaman für dieses heraus zeigen ) )

Der Schatten-Assistent ist das Ohr für Sie
quelle
8
Achten Sie darauf, dass das Testbild richtig optimiert und komprimiert ist. Wenn dies nicht der Fall ist, zeigt die Standardkomprimierung bei Verbindungen durch den Webserver möglicherweise eine höhere Geschwindigkeit als sie tatsächlich ist.
Rauli Rajande
3
Ich habe einen kleinen Trick gefunden, um sicherzustellen, dass Ihr Bild für den Test geeignet ist: Führen Sie den Code mit aktivierter Drosselung des Chrome Dev-Tools aus und prüfen Sie, ob das Ergebnis der Einschränkung entspricht. Hoffe das könnte jemandem helfen.
user284130
3
Beitritt zu Rauli Rajande: Verwenden Sie besser eine Datei, die nicht komprimierbar ist (oder fast), oder Webserver-Komprimierungsmodule können sie erheblich reduzieren und die Maßnahme ungültig machen. Ein JPEG-Bild wäre eine gute Wahl.
Fluxine
1
Haben Sie bei denjenigen, die diesen Javascript-Code erfolgreich verwendet haben, anfangs keine Aufrufe von "download.onload" festgestellt? Genau das erlebe ich und ich versuche immer noch herauszufinden warum.
2
@Dilip kleineres Bild bedeutet weniger genauen Test, es ist absichtlich groß. :)
Shadow Wizard ist Ear For You
78

Nun, dies ist 2017, also haben Sie jetzt die Netzwerkinformations-API (allerdings mit einer eingeschränkten Unterstützung für alle Browser ab sofort), um Informationen zur geschätzten Downlink-Geschwindigkeit zu erhalten:

navigator.connection.downlink

Dies ist eine effektive Bandbreitenschätzung in Mbit / s. Der Browser nimmt diese Schätzung anhand des kürzlich beobachteten Durchsatzes der Anwendungsschicht über kürzlich aktive Verbindungen vor. Der größte Vorteil dieses Ansatzes besteht natürlich darin, dass Sie keine Inhalte nur zur Berechnung der Bandbreite / Geschwindigkeit herunterladen müssen.

Sie können sich dieses und einige andere verwandte Attribute hier ansehen

Aufgrund der eingeschränkten Unterstützung und der unterschiedlichen Implementierungen zwischen den Browsern (Stand November 2017) würde ich dringend empfehlen, dies im Detail zu lesen

Punit S.
quelle
18
Das ist viel Rot in Kann ich verwenden!
Francisco Presencia
2
Ich erhalte damit keine Zahlen über 10 MBit. Gibt es eine Grenze?
Tobi
@Tobi Ich scheine auch nicht höher als 10MBit zu werden, sollte eher 100MBit sein
camjocotem
Was genau ist Downlink? Ist es Download-Geschwindigkeit oder so?
Gacat
@Tobi Ich auch nicht, wenn die Geschwindigkeit über 10
MB
21

Wie ich in dieser anderen Antwort hier auf StackOverflow skizziere , können Sie dies tun, indem Sie den Download von Dateien verschiedener Größen zeitlich festlegen (klein anfangen, hochfahren, wenn die Verbindung dies zuzulassen scheint), durch Cache-Header sicherstellen, dass die Datei wirklich ist vom Remote-Server gelesen und nicht aus dem Cache abgerufen werden. Dies erfordert nicht unbedingt, dass Sie einen eigenen Server haben (die Dateien könnten von S3 oder ähnlichem stammen), aber Sie benötigen einen Ort, an dem Sie die Dateien abrufen können, um die Verbindungsgeschwindigkeit zu testen.

Allerdings sind Bandbreitentests zu einem bestimmten Zeitpunkt notorisch unzuverlässig, da sie von anderen Elementen beeinflusst werden, die in anderen Fenstern heruntergeladen werden, von der Geschwindigkeit Ihres Servers, von Links auf dem Weg usw. usw. Sie können sich jedoch eine ungefähre Vorstellung machen mit dieser Art von Technik.

TJ Crowder
quelle
1
@Jakub: Du müsstest einen Ort zum Hochladen haben, aber es gibt keinen Grund, warum du nicht die gleiche Technik dafür verwenden kannst. Sie können Daten verwenden, die Sie im laufenden Betrieb generieren, oder natürlich einige der Daten, die Sie für den Download-Test heruntergeladen haben, wiederverwenden.
TJ Crowder
Wie würden Sie wissen, wann der Upload abgeschlossen ist?
Jakub Hampl
2
@ Jakub: Eine von mehreren Möglichkeiten. Wenn Sie beispielsweise ein Formular an einen versteckten iframesenden, fragen Sie das iframeoder ein Cookie zum Ausfüllen ab. Wenn Sie ein XMLHttpRequestObjekt verwenden, um den Beitrag zu verfassen, erfolgt ein Rückruf zur Fertigstellung.
TJ Crowder
17

Ich brauchte einen schnellen Weg, um festzustellen, ob die Benutzerverbindungsgeschwindigkeit schnell genug war, um einige Funktionen auf einer Site, an der ich arbeite, zu aktivieren / deaktivieren. Ich habe dieses kleine Skript erstellt, das die durchschnittliche Zeit zum Herunterladen eines einzelnen (kleinen) Bildes a berechnet In meinen Tests funktioniert es ziemlich genau. Ich kann beispielsweise klar zwischen 3G oder Wi-Fi unterscheiden. Vielleicht kann jemand eine elegantere Version oder sogar ein jQuery-Plugin erstellen.

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);
  }
}

dmm79
quelle
1
Die zuverlässigste Antwort in meinem Fall.
Abdalla Arbab
1
Was ist mit dem Upload-Test?
Gumuruh
9

Der Bildtrick ist cool, aber in meinen Tests wurde er vor einigen Ajax-Aufrufen geladen, die ich abschließen wollte.

Die richtige Lösung für 2017 ist die Verwendung eines Arbeitnehmers ( http://caniuse.com/#feat=webworkers ).

Der Arbeiter wird aussehen wie:

/**
 * 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
  );
};

Die js-Datei, die den Worker aufruft:

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);
  }
};

Code aus einem Plone-Paket, das ich geschrieben habe:

alepisa
quelle
5

Es ist besser, Bilder zum Testen der Geschwindigkeit zu verwenden. Wenn Sie sich jedoch mit Zip-Dateien befassen müssen, funktioniert der folgende Code.

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();

Dies funktioniert nicht sehr gut mit Dateien <10 MB. Sie müssen aggregierte Ergebnisse bei mehreren Downloadversuchen ausführen.

Akshar
quelle
3
Die Einfachheit der Antwort gefällt mir sehr gut und ich habe sie für meinen Zweck angepasst: Ich habe für die Zeitstempel auf window.performance.now gewechselt , request.responseType = "blob" (MIME-Typen sind ungültig), request.response.size für die Downloadgröße und 1000000 für die Geschwindigkeitsberechnung (da Mbit / s in SI-Einheiten angegeben werden sollten).
Rupert Rawnsley
1

Dank der Antwort von Punit S können Sie zum Erkennen einer dynamischen Änderung der Verbindungsgeschwindigkeit den folgenden Code verwenden:

navigator.connection.onchange = function () {
 //do what you need to do ,on speed change event
 console.log('Connection Speed Changed');
}
Mehdi Maghrooni
quelle
2
Leider werden nicht alle Browser unterstützt. caniuse.com/#search=netinfo
axelioo