Как определить скорость интернета в JavaScript?


214

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


1
@Jakub, @Ankit: Люди могут использовать Flash для этого, но вам это не нужно . Нет причин, по которым вы не можете сделать это с помощью JavaScript.
TJ Crowder

Это то, что вам нужно: speedof.me/api.html
advncd

Ответы:


288

В некоторой степени это возможно, но не совсем точно, идея заключается в том, чтобы загрузить изображение с известным размером файла, а затем по его 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 и посмотреть, соответствует ли результат ограничениям. (кредит переходит к пользователю 284130 :))

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

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

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


8
Позаботьтесь о том, чтобы тестовое изображение было правильно оптимизировано и сжато. Если это не так, то сжатие по умолчанию на соединениях веб-сервером может показывать скорость, превышающую действительную.
Раули Раджанде

3
Я нашел небольшую хитрость, чтобы убедиться, что ваше изображение подходит для теста: запустите код с включенным регулированием инструмента Chrome dev и посмотрите, соответствует ли результат ограничениям. Надеюсь, это может кому-то помочь.
user284130

3
присоединение к Раули Раджанде: лучше использовать файл, который является несжимаемым (или почти), или модули сжатия веб-сервера могут значительно уменьшить его, лишив законной силы меру. Изображение JPEG было бы хорошим выбором.
Fluxine

1
Для тех, кто успешно использовал этот код Javascript, вы изначально не сталкивались с вызовами "download.onload"? Это именно то, что я испытываю, и я все еще пытаюсь выяснить, почему.

2
@ Dilip меньшее изображение означает менее точный тест, он большой специально. :)
Shadow Wizard - это ухо для тебя

78

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

navigator.connection.downlink

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

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

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


18
Это много красного в я могу использовать!
Франциско Презенсия

2
Я не получаю номера выше 10 Мбит, используя это. Есть ли предел?
Тоби

@ Тоби, кажется, я тоже не получаю больше 10 Мбит, должно быть больше 100 Мбит
camjocotem

Что такое нисходящий канал? Это скорость загрузки или что-то?
Гакат

@ Тоби Я тоже, если скорость превышает 10 Мб, я продолжаю читать 10
Арамиль

21

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

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


1
@Jakub: Вам нужно будет место для загрузки, но нет причин, по которым вы не можете использовать ту же технику для этого. Вы можете использовать данные, которые вы генерируете на лету, или, конечно, вы можете повторно использовать некоторые данные, которые вы загрузили для теста загрузки.
TJ Crowder

Итак, как бы вы узнали, когда загрузка была завершена?
Якуб Хэмпл

2
@Jakub: любым из нескольких способов. iframeНапример, если вы отправляете скрытую форму , вы опрашиваете iframeили файл cookie для завершения. Если вы используете XMLHttpRequestобъект, чтобы сделать сообщение, есть обратный вызов для завершения.
TJ Crowder

18

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


1
Самый надежный ответ, в моем случае.
Абдалла

1
как насчет загрузки теста?
Гумурух

9

Трюк с изображением классный, но в моих тестах он загружался до того, как некоторые вызовы 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

Для проверки скорости лучше использовать изображения. Но если вам приходится иметь дело с 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 МБ. Вам придется запускать агрегированные результаты при нескольких попытках загрузки.


3
Мне очень нравится простота ответа, и я адаптировал его для своих целей: я поменял местами метки времени на window.performance.now , request.responseType = "blob" (типы MIME недопустимы), request.response.size для размер загрузки и 1000000 для расчета скорости (потому что Мбит / с должен быть в единицах СИ).
Руперт Роунсли,

3

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

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

Это должно работать с обоими jQuery.ajaxили угловыми $http.


1

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

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

2
к сожалению, он не поддерживает все браузеры. caniuse.com/#search=netinfo
axelioo
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.