Comment détecter la vitesse d'Internet en JavaScript?


214

Comment puis-je créer une page JavaScript qui détectera la vitesse Internet de l'utilisateur et l'affichera sur la page? Quelque chose comme "votre vitesse Internet est ?? / ?? Kb / s » .


1
@Jakub, @Ankit: Les gens peuvent utiliser Flash pour cela, mais ce n'est pas nécessaire . Aucune raison que vous ne puissiez le faire avec JavaScript.
TJ Crowder du

Voici ce dont vous avez besoin: speedof.me/api.html
advncd

Réponses:


288

Il est possible dans une certaine mesure mais ne sera pas vraiment précis, l'idée est de charger l'image avec une taille de fichier connue, puis de onloadmesurer dans son événement le temps écoulé avant que cet événement ne se déclenche, et de diviser ce temps en taille de fichier image.

Un exemple peut être trouvé ici: Calculer la vitesse en utilisant javascript

Cas de test appliquant le correctif suggéré ici:

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

Une comparaison rapide avec le service de test de vitesse "réel" a montré une petite différence de 0,12 Mbps lors de l'utilisation de la grande image.

Pour garantir l'intégrité du test, vous pouvez exécuter le code avec la limitation de l'outil de développement Chrome activée, puis voir si le résultat correspond à la limitation. (le crédit revient à user284130 :))

Choses importantes à garder à l'esprit:

  1. L'image utilisée doit être correctement optimisée et compressée. Si ce n'est pas le cas, la compression par défaut sur les connexions par le serveur Web peut afficher une vitesse supérieure à ce qu'elle est réellement. Une autre option consiste à utiliser un format de fichier non compressible, par exemple jpg. (merci Rauli Rajande de l'avoir signalé et Fluxine de me l' avoir rappelé )

  2. Le mécanisme de cache cache décrit ci-dessus peut ne pas fonctionner avec certains serveurs CDN, qui peuvent être configurés pour ignorer les paramètres de chaîne de requête, d'où un meilleur réglage des en-têtes de contrôle du cache sur l'image elle-même. (merci orcaman pour avoir signalé ) )


8
Veillez à ce que l'image de test soit correctement optimisée et compressée. Si ce n'est pas le cas, la compression par défaut des connexions par le serveur Web peut afficher une vitesse supérieure à ce qu'elle est réellement.
Rauli Rajande

3
J'ai trouvé une petite astuce pour vous assurer que votre image est adaptée au test: exécutez le code avec la limitation de l'outil de développement Chrome activée et voyez si le résultat correspond à la limitation. J'espère que cela pourrait aider quelqu'un.
user284130

3
rejoindre Rauli Rajande: mieux utiliser un fichier qui n'est pas compressible (ou presque), ou les modules de compression du serveur web peuvent le réduire significativement, invalidant la mesure. Une image jpeg serait un bon choix.
Fluxine

1
Pour ceux qui ont utilisé ce code Javascript avec succès, n'avez-vous rencontré initialement aucun appel à "download.onload"? C'est exactement ce que je vis et j'essaie toujours de savoir pourquoi.

2
@Dilip une image plus petite signifie un test moins précis, c'est grand à dessein. :)
Shadow Wizard est Ear For You

78

Eh bien, nous sommes en 2017, vous avez donc maintenant l'API d'informations réseau (bien qu'avec une prise en charge limitée sur les navigateurs à partir de maintenant) pour obtenir une sorte d' estimation des informations sur la vitesse de liaison descendante:

navigator.connection.downlink

Il s'agit d'une estimation de la bande passante effective en Mbits par seconde. Le navigateur effectue cette estimation à partir du débit de la couche d'application récemment observé sur les connexions récemment actives. Inutile de dire que le plus grand avantage de cette approche est que vous n'avez pas besoin de télécharger de contenu uniquement pour le calcul de la bande passante / vitesse.

Vous pouvez consulter cela et quelques autres attributs connexes ici

En raison de sa prise en charge limitée et des différentes implémentations entre les navigateurs (en novembre 2017), je recommande fortement de lire ceci en détail


18
C'est beaucoup de rouge dans Can I Use!
Francisco Presencia

2
Je n'obtiens pas de nombres supérieurs à 10 Mo en utilisant cela. Y a-t-il une limite?
Tobi

@Tobi Je ne semble pas non plus dépasser 10MBit, devrait plutôt ressembler à 100MBit
camjocotem

Quelle est exactement la liaison descendante? Est-ce la vitesse de téléchargement ou quelque chose?
gacat

@Tobi Moi non plus, si la vitesse est supérieure à 10 Mo, je continue de lire 10
Aramil

21

Comme je le souligne dans cette autre réponse ici sur StackOverflow , vous pouvez le faire en chronométrant le téléchargement de fichiers de différentes tailles (commencez petit, augmentez si la connexion semble le permettre), en vous assurant via les en-têtes de cache et que le fichier est vraiment étant lu à partir du serveur distant et non récupéré du cache. Cela ne nécessite pas nécessairement que vous ayez votre propre serveur (les fichiers peuvent provenir de S3 ou similaire), mais vous aurez besoin d'un endroit pour obtenir les fichiers afin de tester la vitesse de connexion.

Cela dit, les tests de bande passante ponctuels sont notoirement peu fiables, étant donné qu'ils sont impactés par d'autres éléments téléchargés dans d'autres fenêtres, la vitesse de votre serveur, les liens en cours de route, etc., etc. Mais vous pouvez avoir une idée approximative en utilisant ce genre de technique.


1
@Jakub: Vous devez avoir un endroit où télécharger, mais il n'y a aucune raison pour laquelle vous ne pouvez pas utiliser la même technique pour cela. Vous pouvez utiliser les données que vous générez à la volée ou, bien sûr, vous pouvez réutiliser certaines des données que vous avez téléchargées pour le test de téléchargement.
TJ Crowder du

Alors, comment sauriez-vous quand le téléchargement s'est terminé?
Jakub Hampl

2
@Jakub: de plusieurs façons. Si vous soumettez un formulaire à un caché iframe, par exemple, vous interrogez le iframeou un cookie pour l'achèvement. Si vous utilisez un XMLHttpRequestobjet pour faire le post, il y a un rappel pour terminer.
TJ Crowder

18

J'avais besoin d'un moyen rapide pour déterminer si la vitesse de connexion de l'utilisateur était assez rapide pour activer / désactiver certaines fonctionnalités dans un site sur lequel je travaille, j'ai créé ce petit script qui fait la moyenne du temps nécessaire pour télécharger une seule (petite) image a plusieurs fois, cela fonctionne assez précisément dans mes tests, étant capable de distinguer clairement entre la 3G ou le Wi-Fi par exemple, peut-être que quelqu'un peut faire une version plus élégante ou même 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 réponse la plus fiable, dans mon cas.
Abdalla Arbab

1
qu'en est-il du test de téléchargement?
gumuruh

9

L'astuce d'image est cool mais dans mes tests, elle se chargeait avant quelques appels ajax, je voulais être complète.

La bonne solution en 2017 est d'utiliser un travailleur ( http://caniuse.com/#feat=webworkers ).

Le travailleur ressemblera à:

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

Le fichier js qui invoquera le Worker:

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 extrait d'un package Plone que j'ai écrit:


5

Il est préférable d'utiliser des images pour tester la vitesse. Mais si vous devez gérer des fichiers zip, le code ci-dessous fonctionne.

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

Cela ne fonctionnera pas très bien avec des fichiers <10 Mo. Vous devrez exécuter des résultats agrégés sur plusieurs tentatives de téléchargement.


3
J'aime vraiment la simplicité de la réponse et je l'ai adaptée à mon objectif: je suis passé à window.performance.now pour les horodatages, request.responseType = "blob" (les types MIME ne sont pas valides), request.response.size for la taille du téléchargement et 1000000 pour le calcul de la vitesse (car les Mbps doivent être en unités SI).
Rupert Rawnsley


1

grâce à la réponse Punit S, pour détecter les changements dynamiques de vitesse de connexion, vous pouvez utiliser le code suivant:

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

2
malheureusement, il ne prend pas en charge tous les navigateurs. caniuse.com/#search=netinfo
axelioo
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.