【问题标题】:How to detect internet speed in JavaScript?如何在 JavaScript 中检测互联网速度?
【发布时间】:2011-04-03 12:58:44
【问题描述】:

如何创建一个 JavaScript 页面来检测用户的互联网速度并将其显示在页面上?类似“你的网速是??/?? Kb/s”.

【问题讨论】:

  • @Jakub, @Ankit:人们可能会使用 Flash,但您不需要。没有任何理由你不能用 JavaScript 做到这一点。
  • 这就是你需要的:speedof.me/api.html

标签: javascript download-speed


【解决方案1】:

这在某种程度上是可能的,但不会很准确,这个想法是加载具有已知文件大小的图像,然后在其onload 事件中测量直到该事件被触发为止经过了多少时间,并将这段时间划分为图片文件大小。

示例可以在这里找到:Calculate speed using 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"
        ]);
    }
}
&lt;h1 id="progress"&gt;JavaScript is turned off, or your browser is realllllly slow&lt;/h1&gt;

"real" speed test service 的快速比较显示,在使用大图片时有 0.12 Mbps 的微小差异。

为确保测试的完整性,您可以在启用 Chrome 开发工具限制的情况下运行代码,然后查看结果是否符合限制。 (感谢 user284130 :))

要记住的重要事项:

  1. 所使用的图像应经过适当优化和压缩。如果不是,则 Web 服务器对连接的默认压缩可能会显示出比实际更大的速度。另一种选择是使用不可压缩的文件格式,例如.jpg (感谢 Rauli Rajande pointing this out 和 Fluxine reminding me

  2. 上述缓存破坏机制可能不适用于某些 CDN 服务器,可以将其配置为忽略查询字符串参数,从而更好地在图像本身上设置缓存控制标头。 (感谢 orcaman pointing this out

  3. 图像尺寸越大越好。更大的图像会使测试更准确,5 mb 是不错的,但如果你可以使用更大的图像会更好。

【讨论】:

  • 请注意测试图像是否经过适当优化和压缩。如果不是,那么网络服务器对连接的默认压缩可能会显示出比实际更大的速度。
  • 我发现了一个小技巧来确保您的图像适合测试:在启用 Chrome 开发工具限制的情况下运行代码,并查看结果是否符合限制。希望这可以帮助某人。
  • 加入 Rauli Rajande :最好使用不可压缩(或几乎不可压缩)的文件,否则网络服务器压缩模块可能会显着减少它,从而使措施无效。 jpeg 图片是个不错的选择。
  • @Dilip 较小的图像意味着不太准确的测试,这是故意的。 :)
  • @AndrewSchultz 是的,可能是这样。速度测试站点通常足够大,可以在世界各地拥有多台服务器,并使用离用户最近的服务器。此外,可能是托管您在我的代码中使用的文件的服务器的上传限制。
【解决方案2】:

嗯,现在是 2017 年,所以您现在拥有 Network Information API(尽管目前跨浏览器的支持有限)来获取某种估计下行链路速度信息:

navigator.connection.downlink

这是以每秒 Mbits 为单位的有效带宽估计值。浏览器根据最近观察到的最近活动连接中的应用程序层吞吐量进行此估计。不用说,这种方式最大的好处就是不用下载任何内容来计算带宽/速度。

您可以查看此属性以及其他一些相关属性here

由于支持有限且跨浏览器的实现不同(截至 2017 年 11 月),强烈建议详细阅读 this

【讨论】:

  • Can I Use 里面的红太多了!
  • 我没有得到高于 10MBit 的数字。有限制吗?
  • @Tobi 我似乎也没有超过 10MBit,应该更像 100MBit
  • @Tobi 我也没有,如果速度超过 10Mb 我会继续阅读 10
  • @Tobi Chrome 将最大值设置为 10 兆位以停止指纹识别尝试。
【解决方案3】:

我需要一种快速的方法来确定用户连接速度是否足够快以启用/禁用我正在处理的网站中的某些功能,我制作了这个小脚本来平均下载单个(小) 图像多次,它在我的测试中工作得相当准确,例如能够清楚地区分 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);
  }
}

【讨论】:

  • 上传测试呢?
【解决方案4】:

正如我在this other answer here on StackOverflow 中概述的那样,您可以通过定时下载各种大小的文件来做到这一点(从小处开始,如果连接似乎允许,则加速),确保通过缓存头文件确实是从远程服务器读取,而不是从缓存中检索。这并不一定要求您拥有自己的服务器(文件可能来自 S3 或类似的服务器),但您需要从某个地方获取文件以测试连接速度。

也就是说,时间点带宽测试是出了名的不可靠,因为它们会受到其他窗口中下载的其他项目、服务器速度、途中链接等的影响。但你可以得到使用这种技术的粗略想法。

【讨论】:

  • @Jakub:你必须有一个上传的地方,但你没有理由不能使用相同的技术。您可以使用即时生成的数据,当然,您也可以将下载的一些数据重新用于下载测试。
  • 那么您怎么知道上传何时完成?
  • @Jakub:几种方法中的任何一种。例如,如果您向隐藏的iframe 提交表单,则轮询iframe 或cookie 以完成。如果您使用XMLHttpRequest 对象来发布帖子,则会有一个完成回调。
【解决方案5】:

图像技巧很酷,但在我的测试中,它是在我想要完成的一些 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
  );
};

调用Worker的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 包:

【讨论】:

    【解决方案6】:

    最好使用图片来测试速度。但是如果你必须处理 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 的文件。您必须在多次下载尝试时运行汇总结果。

    【讨论】:

    • 我真的很喜欢答案的简单性,并根据我的目的对其进行了调整:我将时间戳换成 window.performance.nowrequest.responseType = "blob"(MIME 类型无效),request.response.size 为下载大小,1000000 为速度计算(因为 Mbps 应该SI 单位)。
    【解决方案7】:

    尽管这已经过时且已得到解答,但我想分享我在 2020 年提出的解决方案

    它具有随时运行的灵活性,并在大于或小于指定 mbps 时运行回调

    您可以通过运行testConnectionSpeed.run(mbps, morefunction, lessfunction)在包含testConnectionSpeed 对象之后的任何位置开始测试

    例如:

    var testConnectionSpeed = {
      imageAddr : "https://upload.wikimedia.org/wikipedia/commons/a/a6/Brandenburger_Tor_abends.jpg", // this is just an example, you rather want an image hosted on your server
      downloadSize : 2707459, // this must match with the image above
      run:function(mbps_max,cb_gt,cb_lt){
        testConnectionSpeed.mbps_max = parseFloat(mbps_max) ? parseFloat(mbps_max) : 0;
        testConnectionSpeed.cb_gt = cb_gt;
        testConnectionSpeed.cb_lt = cb_lt;
        testConnectionSpeed.InitiateSpeedDetection();
      },
      InitiateSpeedDetection: function() {
        window.setTimeout(testConnectionSpeed.MeasureConnectionSpeed, 1);
      },
      result:function(){
        var duration = (endTime - startTime) / 1000;
        var bitsLoaded = testConnectionSpeed.downloadSize * 8;
        var speedBps = (bitsLoaded / duration).toFixed(2);
        var speedKbps = (speedBps / 1024).toFixed(2);
        var speedMbps = (speedKbps / 1024).toFixed(2);
        if(speedMbps >= (testConnectionSpeed.max_mbps ? testConnectionSpeed.max_mbps : 1) ){
          testConnectionSpeed.cb_gt ? testConnectionSpeed.cb_gt(speedMbps) : false;
        }else {
          testConnectionSpeed.cb_lt ? testConnectionSpeed.cb_lt(speedMbps) : false;
        }
      },
      MeasureConnectionSpeed:function() {
        var download = new Image();
        download.onload = function () {
            endTime = (new Date()).getTime();
            testConnectionSpeed.result();
        }
        startTime = (new Date()).getTime();
        var cacheBuster = "?nnn=" + startTime;
        download.src = testConnectionSpeed.imageAddr + cacheBuster;
      }
    }
    
    
    
    
    // start test immediatly, you could also call this on any event or whenever you want
    testConnectionSpeed.run(1.5, function(mbps){console.log(">= 1.5Mbps ("+mbps+"Mbps)")}, function(mbps){console.log("< 1.5Mbps("+mbps+"Mbps)")} )

    我成功地使用它来加载低分辨率媒体以实现慢速互联网连接。您必须尝试一下,因为一方面,图像越大,测试越合理,另一方面,对于慢速连接,测试将花费更长的时间,在我的情况下,我特别不希望慢速连接用户加载大量 MB。

    【讨论】:

    • 不起作用,加上这不是普通的 javascript 有一个错误!
    • 您好,这是普通的 javascript,它可以工作,请参阅我添加的可运行代码 sn-p
    • 还有什么方法可以提高上传速度?
    • @Dani 是的。只需上传文件而不是下载文件。
    【解决方案8】:

    感谢 Punit S 的回答,为了检测动态连接速度变化,您可以使用以下代码:

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

    【讨论】:

    【解决方案9】:

    我需要类似的东西,所以我写了https://github.com/beradrian/jsbandwidth。这是https://code.google.com/p/jsbandwidth/ 的重写。

    这个想法是通过 Ajax 进行两次调用,一个用于下载,另一个通过 POST 上传。

    它应该适用于 jQuery.ajax 或 Angular $http

    【讨论】:

      【解决方案10】:

      改进了 John Smith 的回答,这是一个不错且干净的解决方案,它返回一个 Promise,因此可以与 async/await 一起使用。返回以 Mbps 为单位的值。

      const imageAddr = 'https://upload.wikimedia.org/wikipedia/commons/a/a6/Brandenburger_Tor_abends.jpg';
      const downloadSize = 2707459; // this must match with the image above
      
      let startTime, endTime;
      async function measureConnectionSpeed() {
        startTime = (new Date()).getTime();
        const cacheBuster = '?nnn=' + startTime;
      
        const download = new Image();
        download.src = imageAddr + cacheBuster;
        // this returns when the image is finished downloading
        await download.decode();
        endTime = (new Date()).getTime();
        const duration = (endTime - startTime) / 1000;
        const bitsLoaded = downloadSize * 8;
        const speedBps = (bitsLoaded / duration).toFixed(2);
        const speedKbps = (speedBps / 1024).toFixed(2);
        const speedMbps = (speedKbps / 1024).toFixed(2);
        return Math.round(Number(speedMbps));
      }
      

      【讨论】:

        【解决方案11】:

        //JUST AN EXAMPLE, PLEASE USE YOUR OWN PICTURE!
        var imageAddr = "https://i.ibb.co/sPbbkkZ/pexels-lisa-1540258.jpg"; 
        var downloadSize = 10500000; //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"
                ]);
            }
        }
        &lt;h1 id="progress"&gt;JavaScript is turned off, or your browser is realllllly slow&lt;/h1&gt;

        【讨论】:

          【解决方案12】:

          迷你sn-p:

          var speedtest = {};
          function speedTest_start(name) { speedtest[name]= +new Date(); }
          function speedTest_stop(name) { return +new Date() - speedtest[name] + (delete 
          speedtest[name]?0:0); }
          

          像这样使用:

          speedTest_start("test1");
          
          // ... some code
          
          speedTest_stop("test1");
          // returns the time duration in ms
          

          还可以进行更多测试:

          speedTest_start("whole");
          
          // ... some code
          
          speedTest_start("part");
          
          // ... some code
          
          speedTest_stop("part");
          // returns the time duration in ms of "part"
          
          // ... some code
          
          speedTest_stop("whole");
          // returns the time duration in ms of "whole"
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-07-28
            • 1970-01-01
            • 1970-01-01
            • 2022-11-19
            • 2017-09-07
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多