JavaScriptでインターネット速度を検出する方法は?


213

ユーザーのインターネット速度を検出してページに表示するJavaScriptページを作成するにはどうすればよいですか?何かのように「あなたのインターネットの速度は?? / ??です Kb / s」


1
@ Jakub、@ Ankit:人々はFlashを使用するかもしれません、そうする必要ありません。JavaScriptでそれを実行できない理由はありません。
TJクラウダー、2011

これが必要なものです: 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 Mbpsの小さな違いが示されました。

テストの整合性を確保するには、Chrome開発ツールのスロットルを有効にしてコードを実行し、結果が制限と一致するかどうかを確認します。(クレジットはuser284130に送られます :))

覚えておくべき重要なこと:

  1. 使用する画像は適切に最適化され、圧縮されている必要があります。そうでない場合、Webサーバーによる接続のデフォルトの圧縮は、実際よりも速い速度を示す可能性があります。別のオプションは、jpgなどの非圧縮ファイル形式を使用することです。指摘してくれたRauli Rajande と私に思い出させてくれた Fluxineに感謝

  2. 上記のキャッシュ無効化メカニズムは一部のCDNサーバーでは機能しない可能性があります。CDNサーバーはクエリ文字列パラメーターを無視するように構成できるため、イメージ自体のキャッシュ制御ヘッダーをより適切に設定できます。これ指摘してくれたorcamanに感謝)


8
テストイメージが適切に最適化および圧縮されていることを確認してください。そうでない場合、Webサーバーによる接続のデフォルトの圧縮は、実際よりも速い速度を示す可能性があります。
Rauli Rajande 2014

3
画像がテストに適していることを確認するための小さなトリックが見つかりました。Chrome開発ツールのスロットルを有効にしてコードを実行し、結果が制限と一致するかどうかを確認します。これが誰かを助けることを願っています。
user284130 2014

3
Rauli Rajandeへの参加:非圧縮(またはほぼ)ファイルを使用することをお勧めします。そうでない場合、Webサーバー圧縮モジュールによってファイルが大幅に削減され、測定が無効になります。jpeg画像は良い選択です。
Fluxine、2015

1
このJavascriptコードを正常に使用したことがある人にとって、最初に「download.onload」への呼び出しはありませんでしたか?これはまさに私が経験していることであり、私はまだ理由を見つけようとしています。

2
@Dilip小さい画像は、テストの精度が低下することを意味し、意図的に大きくなります。:)
シャドウウィザードは

78

さて、これは2017年ですので、ネットワーク情報API(現在のところ、ブラウザー全体でサポートが制限されています)を使用して、何らかの推定ダウンリンク速度情報を取得できます。

navigator.connection.downlink

これは、1秒あたりのMbitsでの有効な帯域幅の見積もりです。ブラウザーは、最近アクティブな接続全体で最近観測されたアプリケーションレイヤーのスループットからこの推定を行います。言うまでもなく、このアプローチの最大の利点は、帯域幅/速度の計算のためだけにコンテンツをダウンロードする必要がないことです。

これと他のいくつかの関連属性をここで見ることができます

(2017年11月の時点で)ブラウザー間でサポートが制限され、実装が異なるため、これを詳細に読むことを強くお勧めします


18
それは「私は使用できます」の赤がたくさんあります。
Francisco Presencia

2
これを使用して10MBitを超える数値を取得しません。制限はありますか?
トビ

@Tobi 10MBitを超えないようで、100MBitに近いはずです
camjocotem

ダウンリンクとは正確には何ですか?ダウンロード速度かそれとも何か?
gacat

@Tobi Meも、速度が10Mbを超えている場合、10を読み続けます
Aramil

21

StackOverflowこの他の回答の概要を説明しているように、さまざまなサイズのファイルのダウンロードのタイミングを調整することで、接続を許可していると思われる場合は、小さいサイズから開始し、キャッシュヘッダーを介して、ファイルが本当にリモートサーバーから読み取られ、キャッシュから取得されていません。これは必ずしも独自のサーバーを持っている必要はありません(ファイルはS3または同様のものから来る可能性があります)が、接続速度をテストするためにファイルを取得する場所が必要になります。

とはいえ、ポイントインタイム帯域幅テストは、他のウィンドウでダウンロードされている他のアイテム、サーバーの速度、転送中のリンクなどの影響を受けるため、信頼性が低いことで悪名高く知られています。この種のテクニックを使用します。


1
@Jakub:アップロードする場所が必要ですが、同じ手法を使用できない理由はありません。オンザフライで生成したデータを使用することも、もちろん、ダウンロードテスト用にダウンロードしたデータの一部を再利用することもできます。
TJクラウダー、2011

それで、アップロードがいつ完了したかをどのようにして知ることができますか?
Jakub Hampl 2011

2
@Jakub:いくつかの方法があります。たとえば、非表示にフォームiframeを送信すると、iframeまたはCookieをポーリングして完了を確認します。XMLHttpRequestオブジェクトを使用して投稿を行う場合、完了のためのコールバックがあります。
TJクラウダー2011

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
私の場合、最も信頼できる答え。
Abdalla Arbab

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ファイル:

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

これは、10MB未満のファイルではうまく機能しません。複数のダウンロード試行で集計結果を実行する必要があります。


3
私は本当に答えのシンプルさのような、私は私の目的のためにそれを適応している:私はするスワップwindow.performance.now、タイムスタンプのためにrequest.responseType =「ブロブ」(MIMEタイプが有効でない)、request.response.sizeについてダウンロードサイズ、および速度計算に1000000(MbpsはSI単位である必要があるため)。
Rupert Rawnsley 2017


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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.