Як виявити швидкість Інтернету в JavaScript?


213

Як я можу створити сторінку JavaScript, яка буде визначати швидкість інтернету користувача та показувати його на сторінці? Щось на кшталт "швидкість вашого Інтернету є ?? / ?? Кб / с ” .


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

Це те, що вам потрібно: speedof.me/api.html
advncd

Відповіді:


287

Це можливо до певної міри, але не буде по-справжньому точним, ідея полягає у завантаженні зображення з відомим розміром файлу, а потім у його 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. (дякую Раулі Раджанде, що вказав на це, і Флуксин, що нагадав мені )

  2. Описаний вище механізм розгортання кешу може не працювати з деякими серверами CDN, які можна налаштувати на ігнорування параметрів рядка запиту, отже, краще встановити заголовки кеш-керування для самого зображення. (дякую orcaman за вказівку на це ) )


8
Слідкуйте за тим, щоб тестове зображення було оптимізовано та стисло. Якщо це не так, то компресія за замовчуванням на з'єднаннях веб-сервером може показувати швидкість, більшу, ніж є насправді.
Раулі Раджанде

3
Я знайшов невелику хитрість, щоб переконатися, що ваше зображення підходить для тестування: запустіть код із увімкненим увімкненням інструмента для розробки інструмента Chrome, і подивіться, чи відповідає результат обмеженню. Сподіваюся, це може комусь допомогти.
користувач284130

3
приєднання до Раулі Раджанде: краще використовувати файл, який не є стисливим (або майже), або модулі стиснення веб-сервера можуть значно зменшити його, анулюючи міру. Зображення jpeg було б хорошим вибором.
Флюксин

1
Для тих, хто успішно використовував цей код Javascript, ви спочатку не стикалися з жодними дзвінками, які перейшли на "download.onload"? Це саме те, що я переживаю, і я все ще намагаюся з’ясувати, чому.

2
@Dilip менший образ означає менш точний тест, він великий за призначенням. :)
Shadow Wizard is Ear For You

78

Ну, це 2017 рік, тож тепер у вас є API інформації про мережу (хоч і з обмеженою підтримкою в браузерах на сьогодні), щоб отримати якесь оцінку інформації про швидкості низхідній лінії:

navigator.connection.downlink

Це ефективна оцінка пропускної здатності в Мбіт / с. Веб-переглядач робить цю оцінку за останнім часом спостережуваного рівня програми через останні активні з'єднання. Потрібно сказати, що найбільшою перевагою такого підходу є те, що вам не потрібно завантажувати будь-який вміст лише для обчислення пропускної здатності / швидкості.

Ви можете ознайомитись із цим та парою інших пов’язаних атрибутів тут

З - за його обмежену підтримку і різних реалізацій в різних браузерах (за станом на листопад 2017 року), настійно рекомендую прочитати це докладно


18
Це багато червоного в Чи можу я використовувати!
Francisco Presencia

2
Я не отримую цифри вище 10MBit, використовуючи це. Чи є обмеження?
Тобі

@Tobi Я також, здається, не перевищував 10MBit, повинен бути більше схожий на 100MBit
camjocotem

Що саме по низхідній лінії? Це швидкість завантаження чи щось таке?
гакат

@Tobi Мені ні, якщо швидкість перевищує 10 Мбіт, я продовжую читати 10
Араміль

21

Як я окреслюю в цій іншій відповіді тут на StackOverflow , ви можете зробити це, встановивши тимчасове завантаження файлів різного розміру (почніть невеликий, нарощуйте, якщо з'єднання здається, що це дозволяє), забезпечивши через заголовки кешу і таке, що файл справді читається з віддаленого сервера і не витягується з кешу. Це не обов'язково вимагає наявності власного сервера (файли можуть надходити з S3 або подібного), але вам потрібно буде десь дістати файли, щоб перевірити швидкість з'єднання.

Однак, тести пропускної спроможності в часі часу є сумнівно ненадійними, оскільки на них впливають інші елементи, які завантажуються в інші вікна, швидкість роботи вашого сервера, посилання на маршруті тощо тощо. Але ви можете отримати орієнтовне уявлення використовуючи цю техніку.


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

То як би ви знали, коли завантаження закінчилося?
Якуб Гампл

2
@Jakub: будь-яким із кількох способів. Наприклад, якщо ви подаєте форму в приховану iframe, наприклад, ви опитуєте iframeфайл cookie або файл cookie для його заповнення. Якщо ви використовуєте XMLHttpRequestоб'єкт для публікації, є зворотний виклик для завершення.
TJ Crowder

17

Мені потрібен був швидкий спосіб визначити, чи була швидкість з'єднання користувачів достатньо швидкою, щоб увімкнути / вимкнути деякі функції на веб-сайті, над яким я працюю, я створив цей маленький сценарій, який в середньому витрачає час на завантаження одного (невеликого) зображення У багатьох тестах вона працює досить точно, маючи можливість чітко розмежувати наприклад 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

Краще використовувати зображення для тестування швидкості. Але якщо вам доведеться мати справу з поштовими файлами, наведений нижче код працює.

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.