如何在 JavaScript 中检测互联网速度?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5529718/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 17:40:20  来源:igfitidea点击:

How to detect internet speed in JavaScript?

javascriptdownload-speed

提问by Sharon Haim Pour

How can I create a JavaScript page that will detect the user's internet speed and show it on the page? Something like “your internet speed is ??/?? Kb/s”.

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

回答by Shadow Wizard is Ear For You

It's possible to some extent but won't be really accurate, the idea is load image with a known file size then in its onloadevent measure how much time passed until that event was triggered, and divide this time in the image file size.

这在某种程度上是可能的,但不是很准确,这个想法是加载具有已知文件大小的图像,然后在其onload事件中测量触发该事件之前经过的时间,并将这段时间除以图像文件大小。

Example can be found here: Calculate speed using javascript

示例可以在这里找到:Calculate speed using javascript

Test case applying the fix suggested there:

应用此处建议的修复程序的测试用例:

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

Quick comparison with "real" speed test serviceshowed small difference of 0.12 Mbps when using big picture.

“真实”速度测试服务的快速比较显示,在使用大图片时,只有 0.12 Mbps 的微小差异。

To ensure the integrity of the test, you can run the code with Chrome dev tool throttling enabled and then see if the result matches the limitation. (credit goes to user284130:))

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

Important things to keep in mind:

要记住的重要事项:

  1. The image being used should be properly optimized and compressed. If it isn't, then default compression on connections by the web server might show speed bigger than it actually is. Another option is using uncompressible file format, e.g. jpg. (thanks Rauli Rajande for pointing this outand Fluxine for reminding me)

  2. The cache buster mechanism described above might not work with some CDN servers, which can be configured to ignore query string parameters, hence better setting cache control headers on the image itself. (thanks orcaman for pointing this out))

  1. 正在使用的图像应适当优化和压缩。如果不是,则 Web 服务器对连接的默认压缩可能会显示比实际速度更大的速度。另一种选择是使用不可压缩的文件格式,例如 jpg。(感谢 Rauli Rajande指出这一点和 Fluxine提醒我

  2. 上面描述的缓存破坏器机制可能不适用于某些 CDN 服务器,这些服务器可以配置为忽略查询字符串参数,因此更好地在图像本身上设置缓存控制标头。(感谢 orcaman指出这一点

回答by Punit S

Well, this is 2017 so you now have Network Information API (albeit with a limited support across browsers as of now) to get some sort of estimatedownlink speed information:

好吧,这是 2017 年,因此您现在拥有网络信息 API(尽管目前对浏览器的支持有限)来获取某种估计的下行链路速度信息:

navigator.connection.downlink

This is effective bandwidth estimate in Mbits per sec. The browser makes this estimate from recently observed application layer throughput across recently active connections. Needless to say, the biggest advantage of this approach is that you need not download any content just for bandwidth/ speed calculation.

这是以每秒 Mbits 为单位的有效带宽估计。浏览器根据最近观察到的跨最近活动连接的应用层吞吐量进行此估计。毋庸置疑,这种方法的最大优点是您无需下载任何内容仅用于带宽/速度计算。

You can look at this and a couple of other related attributes here

您可以在此处查看此内容以及其他一些相关属性

Due to it's limited support and different implementations across browsers (as of Nov 2017), would strongly recommend read thisin detail

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

回答by T.J. Crowder

As I outline in this other answer here on StackOverflow, you can do this by timing the download of files of various sizes (start small, ramp up if the connection seems to allow it), ensuring through cache headers and such that the file is really being read from the remote server and not being retrieved from cache. This doesn't necessarily require that you have a server of your own (the files could be coming from S3or similar), but you will need somewhere to get the files from in order to test connection speed.

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

That said, point-in-time bandwidth tests are notoriously unreliable, being as they are impacted by other items being downloaded in other windows, the speed of your server, links en route, etc., etc. But you can get a rough idea using this sort of technique.

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

回答by dmm79

I needed a quick way to determine if the user connection speed was fast enough to enable/disable some features in a site I'm working on, I made this little script that averages the time it takes to download a single (small) image a number of times, it's working pretty accurately in my tests, being able to clearly distinguish between 3G or Wi-Fi for example, maybe someone can make a more elegant version or even a jQuery plugin.

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

回答by alepisa

The image trick is cool but in my tests it was loading before some ajax calls I wanted to be complete.

图像技巧很酷,但在我的测试中,它是在我想要完成的一些 ajax 调用之前加载的。

The proper solution in 2017 is to use a worker (http://caniuse.com/#feat=webworkers).

2017 年的正确解决方案是使用工人 ( http://caniuse.com/#feat=webworkers)。

The worker will look like:

工人看起来像:

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

The js file that will invoke the Worker:

将调用 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);
  }
};

Code taken from a Plone package I wrote:

从我写的 Plone 包中提取的代码:

回答by Akshar

It's better to use images for testing the speed. But if you have to deal with zip files, the below code works.

最好使用图像来测试速度。但是如果你必须处理 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();

This will not work very well with files < 10MB. You will have to run aggregated results on multiple download attempts.

对于小于 10MB 的文件,这不会很好地工作。您必须在多次下载尝试中运行汇总结果。

回答by Adrian Ber

I needed something similar, so I wrote https://github.com/beradrian/jsbandwidth. This is a rewrite of https://code.google.com/p/jsbandwidth/.

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

The idea is to make two calls through Ajax, one to download and the other to upload through POST.

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

It should work with both jQuery.ajaxor Angular $http.

它应该与两者jQuery.ajax或 Angular 一起使用$http

回答by Mehdi Maghrooni

thanks to Punit S answer, for detecting dynamic connection speed change, you can use the following code :

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

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