¿Cómo detectar la velocidad de internet en JavaScript?


213

¿Cómo puedo crear una página de JavaScript que detecte la velocidad de Internet del usuario y la muestre en la página? Algo así como "su velocidad de internet es ?? / ?? Kb / s " .


1
@Jakub, @Ankit: las personas pueden usar Flash para ello, pero no es necesario . No hay razón para que no pueda hacerlo con JavaScript.
TJ Crowder

Esto es lo que necesita: speedof.me/api.html
advncd

Respuestas:


287

Es posible hasta cierto punto, pero no será realmente preciso, la idea es cargar la imagen con un tamaño de archivo conocido y, en su onloadcaso, medir cuánto tiempo pasó hasta que se activó ese evento y dividir este tiempo en el tamaño del archivo de imagen.

El ejemplo se puede encontrar aquí: calcular la velocidad usando javascript

Caso de prueba aplicando la solución sugerida allí:

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

La comparación rápida con el servicio de prueba de velocidad "real" mostró una pequeña diferencia de 0,12 Mbps cuando se usa una imagen general.

Para garantizar la integridad de la prueba, puede ejecutar el código con la limitación de la herramienta de desarrollo de Chrome habilitada y luego ver si el resultado coincide con la limitación. (el crédito va al usuario284130 :))

Cosas importantes a tener en cuenta:

  1. La imagen que se usa debe estar correctamente optimizada y comprimida. Si no es así, la compresión predeterminada en las conexiones del servidor web puede mostrar una velocidad mayor de lo que realmente es. Otra opción es utilizar un formato de archivo no comprimible, por ejemplo, jpg. (gracias Rauli Rajande por señalar esto y Fluxine por recordármelo )

  2. El mecanismo de bloqueo de caché descrito anteriormente podría no funcionar con algunos servidores CDN, que pueden configurarse para ignorar los parámetros de la cadena de consulta, por lo tanto, es mejor configurar los encabezados de control de caché en la imagen misma. (gracias orcaman por señalar esto ) )


8
Tenga cuidado de que la imagen de prueba esté correctamente optimizada y comprimida. Si no es así, la compresión predeterminada en las conexiones del servidor web puede mostrar una velocidad mayor de lo que realmente es.
Rauli Rajande

3
Encontré un pequeño truco para garantizar que su imagen sea adecuada para la prueba: ejecute el código con la aceleración de la herramienta de desarrollo de Chrome habilitada, y vea si el resultado coincide con la limitación. Espero que esto pueda ayudar a alguien.
user284130

3
unirse a Rauli Rajande: mejor use un archivo que no se pueda comprimir (o casi), o los módulos de compresión del servidor web pueden reducirlo significativamente, invalidando la medida. Una imagen JPEG sería una buena opción.
Fluxine

1
Para aquellos que han utilizado con éxito este código Javascript, ¿inicialmente no encontraron llamadas para "download.onload"? Esto es exactamente lo que estoy experimentando y todavía estoy tratando de descubrir por qué.

2
@Dilip imagen más pequeña significa prueba menos precisa, es grande a propósito. :)
Shadow Wizard es Ear For You

78

Bueno, esto es 2017, por lo que ahora tiene API de información de red (aunque con un soporte limitado en todos los navegadores a partir de ahora) para obtener algún tipo de información estimada de velocidad de enlace descendente:

navigator.connection.downlink

Esta es una estimación efectiva del ancho de banda en Mbits por segundo. El navegador realiza esta estimación a partir del rendimiento de la capa de aplicación recientemente observado a través de conexiones activas recientemente. No es necesario decir que la mayor ventaja de este enfoque es que no necesita descargar ningún contenido solo para calcular el ancho de banda / velocidad.

Puedes ver esto y otros atributos relacionados aquí

Debido a su soporte limitado y diferentes implementaciones en todos los navegadores (a partir de noviembre de 2017), recomendaría leer esto en detalle


18
¡Eso es mucho rojo en Can I Use!
Francisco Presencia

2
No obtengo números superiores a 10MBit usando esto. ¿Hay un límite?
Tobi

@Tobi Tampoco parece que supere los 10MBit, debería ser más como 100MBit
camjocotem

¿Qué es exactamente el enlace descendente? ¿Es la velocidad de descarga o algo así?
gacat

@Tobi Me tampoco, si la velocidad supera los 10Mb sigo leyendo 10
Aramil

21

Como describo en esta otra respuesta aquí en StackOverflow , puede hacerlo cronometrando la descarga de archivos de varios tamaños (comience con poco, aumente si la conexión parece permitirlo), asegurándose a través de los encabezados de caché y tal que el archivo sea realmente se lee desde el servidor remoto y no se recupera de la memoria caché. Esto no requiere necesariamente que tenga un servidor propio (los archivos podrían provenir de S3 o similar), pero necesitará un lugar desde donde obtener los archivos para probar la velocidad de conexión.

Dicho esto, las pruebas de ancho de banda en un punto en el tiempo son notoriamente poco confiables, ya que se ven afectadas por otros elementos que se descargan en otras ventanas, la velocidad de su servidor, enlaces en ruta, etc., etc. Pero puede tener una idea aproximada usando este tipo de técnica.


1
@Jakub: Tendrías que tener un lugar para subir, pero no hay razón para que no puedas usar la misma técnica para eso. Puede utilizar los datos que genera sobre la marcha o, por supuesto, puede reutilizar algunos de los datos que descargó para la prueba de descarga.
TJ Crowder

Entonces, ¿cómo saber cuándo se completó la carga?
Jakub Hampl

2
@Jakub: Cualquiera de varias maneras. Si envía un formulario a un oculto iframe, por ejemplo, sondea el iframeo una cookie para completar. Si usa un XMLHttpRequestobjeto para hacer la publicación, hay una devolución de llamada para completar.
TJ Crowder

17

Necesitaba una forma rápida de determinar si la velocidad de conexión del usuario era lo suficientemente rápida como para habilitar / deshabilitar algunas funciones en un sitio en el que estoy trabajando, hice este pequeño script que promedia el tiempo que toma descargar una sola imagen (pequeña) varias veces, funciona con bastante precisión en mis pruebas, pudiendo distinguir claramente entre 3G o Wi-Fi, por ejemplo, tal vez alguien pueda hacer una versión más elegante o incluso un complemento 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 respuesta más confiable, en mi caso.
Abdalla Arbab

1
¿Qué pasa con la prueba de carga?
Gumuruh

9

El truco de la imagen es genial, pero en mis pruebas se estaba cargando antes de algunas llamadas ajax que quería completar.

La solución adecuada en 2017 es utilizar un trabajador ( http://caniuse.com/#feat=webworkers ).

El trabajador se verá así:

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

El archivo js que invocará al trabajador:

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

Código tomado de un paquete de Plone que escribí:


5

Es mejor usar imágenes para probar la velocidad. Pero si tiene que lidiar con archivos zip, el siguiente código funciona.

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

Esto no funcionará muy bien con archivos <10 MB. Tendrá que ejecutar resultados agregados en múltiples intentos de descarga.


3
Realmente me gusta la simplicidad de la respuesta y la he adaptado para mi propósito: cambié a window.performance.now por las marcas de tiempo, request.responseType = "blob" (los tipos MIME no son válidos), request.response.size para el tamaño de descarga y 1000000 para el cálculo de la velocidad (porque los Mbps deben estar en unidades SI).
Rupert Rawnsley


1

Gracias a la respuesta de Punit S, para detectar el cambio dinámico de la velocidad de conexión, puede usar el siguiente código:

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

2
desafortunadamente no es compatible con todos los navegadores. caniuse.com/#search=netinfo
axelioo
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.