Как определить скорость интернета в JavaScript? - PullRequest
183 голосов
/ 03 апреля 2011

Как мне создать страницу JavaScript, которая будет определять скорость интернета пользователя и отображать ее на странице?Что-то вроде «у вас скорость интернета ?? / ??Kb / s».

Ответы [ 8 ]

264 голосов
/ 03 апреля 2011

В некоторой степени это возможно, но не совсем точно, идея заключается в том, чтобы загрузить изображение с известным размером файла, а затем в его событии onload измерить, сколько времени прошло, пока это событие не было запущено, и разделить это время на размер файла изображения.

Пример можно найти здесь: Рассчитать скорость с помощью JavaScript

Тестовый пример с предложенным там исправлением:

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

Быстрое сравнение с «реальной» услугой тестирования скорости показало небольшую разницу в 0,12 Мбит / с при использовании большой картинки.

Чтобы обеспечить целостность теста, вы можете запустить код с включенным регулированием инструмента Chrome dev, а затем посмотреть, соответствует ли результат ограничениям. (кредит поступает на user284130 :))

Важные вещи, которые нужно иметь в виду:

  1. Используемое изображение должно быть правильно оптимизировано и сжато. Если это не так, то сжатие по умолчанию на соединениях веб-сервером может показывать скорость, превышающую фактическую. Другим вариантом является использование несжимаемого формата файла, например, JPG. (спасибо Раули Раджанде за , указавшему на это и Fluxine за , напомнившему мне )

  2. Описанный выше механизм блокировки кэша может не работать с некоторыми серверами CDN, которые можно настроить так, чтобы они игнорировали параметры строки запроса, следовательно, лучше установить заголовки управления кэшем на самом образе. (спасибо orcaman за указав это ) )

47 голосов
/ 27 ноября 2017

Что ж, это 2017 год, так что теперь у вас есть API информации о сети (хотя и с ограниченной поддержкой браузеров на данный момент), чтобы получить какую-то оценку информации о скорости нисходящей линии связи:

navigator.connection.downlink

Это эффективная оценка пропускной способности в Мбит / с. Браузер делает эту оценку исходя из недавно наблюдаемой пропускной способности уровня приложения по недавно активным соединениям. Само собой разумеется, что наибольшим преимуществом этого подхода является то, что вам не нужно загружать какой-либо контент только для расчета пропускной способности / скорости.

Вы можете посмотреть на это и несколько других связанных атрибутов здесь

Из-за ограниченной поддержки и различных реализаций в разных браузерах (по состоянию на ноябрь 2017 г.) настоятельно рекомендуем прочитать эту подробно

19 голосов
/ 03 апреля 2011

Как я обрисовал в общих чертах этот другой ответ здесь, в StackOverflow , вы можете сделать это, синхронизировав загрузку файлов различных размеров (начните с малого, увеличивайте, если соединение, кажется, позволяет это), обеспечивая через заголовки кэша и такие, что файл действительно читается с удаленного сервера и не извлекается из кэша. Это не обязательно требует наличия собственного сервера (файлы могут быть получены из S3 или аналогичного), но вам нужно где-то получить файлы, чтобы проверить скорость соединения.

Тем не менее, тесты пропускной способности на определенный момент времени, как известно, ненадежны, поскольку на них влияют другие элементы, загружаемые в другие окна, скорость вашего сервера, ссылки в пути и т. Д., И т. Д., Но вы можете получить грубая идея с использованием такого рода техники.

13 голосов
/ 27 января 2014

Мне нужен был быстрый способ определить, была ли скорость соединения с пользователем достаточно высокой, чтобы включить / отключить некоторые функции на сайте, над которым я работаю, я сделал этот небольшой скрипт, который усредняет время, необходимое для загрузки одной (небольшой ) несколько раз, в моих тестах он работает довольно точно, например, он может четко различать 3G или Wi-Fi, может быть, кто-то может сделать более элегантную версию или даже плагин 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);
  }
}
7 голосов
/ 02 марта 2017

Трюк с изображением классный, но в моих тестах он загружался до того, как некоторые ajax-вызовы я хотел завершить.

Правильное решение в 2017 году - использовать работника (http://caniuse.com/#feat=webworkers).

Рабочий будет выглядеть так:

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

Файл js, который вызовет 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);
  }
};

Код взят из пакета Plone, который я написал:

5 голосов
/ 01 июля 2015

Лучше использовать изображения для проверки скорости. Но если вам приходится иметь дело с zip-файлами, приведенный ниже код работает.

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

Это не очень хорошо работает с файлами <10 МБ. Вам придется запускать агрегированные результаты при нескольких попытках загрузки. </p>

3 голосов
/ 10 июля 2015

Мне нужно что-то подобное, поэтому я написал https://github.com/beradrian/jsbandwidth. Это переписать https://code.google.com/p/jsbandwidth/.

Идея состоит в том, чтобы сделать два вызова через Ajax, один для загрузки, а другой для загрузки через POST.

Должен работать как с jQuery.ajax, так и с Angular $http.

1 голос
/ 27 января 2019

благодаря ответу Punit S, для определения динамического изменения скорости соединения вы можете использовать следующий код:

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