จะตรวจจับความเร็วอินเทอร์เน็ตใน JavaScript ได้อย่างไร?


214

ฉันจะสร้างหน้า JavaScript ที่จะตรวจจับความเร็วอินเทอร์เน็ตของผู้ใช้และแสดงบนหน้าได้อย่างไร บางอย่างเช่น“ ความเร็วอินเทอร์เน็ตของคุณคือ ?? / ?? Kb / s”


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 Mbps เมื่อใช้ภาพใหญ่

เพื่อความสมบูรณ์ของการทดสอบคุณสามารถเรียกใช้รหัสด้วยการเปิดใช้งานการควบคุมปริมาณเครื่องมือ dev ของ Chrome และดูว่าผลลัพธ์ตรงกับข้อ จำกัด หรือไม่ (เครดิตไปที่ผู้ใช้284130 :))

สิ่งสำคัญที่ควรทราบ:

  1. รูปภาพที่ใช้ควรได้รับการปรับและบีบอัดอย่างเหมาะสม หากไม่เป็นเช่นนั้นการบีบอัดค่าเริ่มต้นของการเชื่อมต่อโดยเว็บเซิร์ฟเวอร์อาจแสดงความเร็วที่มากกว่าที่เป็นจริง อีกทางเลือกหนึ่งคือการใช้รูปแบบไฟล์ที่ไม่สามารถบีบอัดได้เช่น jpg (ขอบคุณ Rauli Rajande ที่ชี้เรื่องนี้และ Fluxine เพื่อเตือนฉัน )

  2. กลไกแคชบัสเตอร์ที่อธิบายข้างต้นอาจไม่ทำงานกับเซิร์ฟเวอร์ CDN บางตัวซึ่งสามารถกำหนดค่าให้ละเว้นพารามิเตอร์สตริงคิวรีได้ดังนั้นการตั้งค่าส่วนหัวควบคุมแคชบนรูปภาพนั้นดีกว่า (ขอบคุณ orcaman สำหรับการชี้สิ่งนี้ ) )


8
ระวังว่าภาพทดสอบนั้นได้รับการปรับและบีบอัดอย่างเหมาะสม หากไม่เป็นเช่นนั้นการบีบอัดค่าเริ่มต้นในการเชื่อมต่อโดยเว็บเซิร์ฟเวอร์อาจแสดงความเร็วที่ใหญ่กว่าที่เป็นจริง
Rauli Rajande

3
ฉันพบเคล็ดลับเล็กน้อยเพื่อให้แน่ใจว่าภาพของคุณเหมาะสำหรับการทดสอบ: เรียกใช้โค้ดด้วยการเปิดใช้งานการควบคุมปริมาณเครื่องมือ dev dev ของ Chrome และดูว่าผลลัพธ์ตรงกับข้อ จำกัด หรือไม่ หวังว่านี่จะช่วยคนได้
284130

3
การเข้าร่วม Rauli Rajande: ควรใช้ไฟล์ที่ไม่สามารถบีบอัดได้ (หรือเกือบ) ดีกว่าหรือโมดูลการบีบอัดเว็บเซิร์ฟเวอร์อาจลดขนาดลงอย่างมาก ภาพ jpeg จะเป็นทางเลือกที่ดี
Fluxine

1
สำหรับผู้ที่ใช้รหัส Javascript นี้สำเร็จคุณไม่พบการโทรไปที่ "download.onload" หรือไม่? นี่คือสิ่งที่ฉันกำลังประสบอยู่และฉันยังคงพยายามหาสาเหตุ

2
@ ภาพขนาดเล็กลงหมายถึงการทดสอบที่แม่นยำน้อยกว่า :)
Shadow Wizard คือ Ear For You

78

ดีนี้เป็น 2017 ดังนั้นตอนนี้คุณมีข้อมูลเครือข่าย API (แม้จะมีการสนับสนุนที่ จำกัด เบราว์เซอร์ ณ ขณะนี้) ที่จะได้รับการจัดเรียงของบางประมาณการข้อมูลความเร็ว downlink:

navigator.connection.downlink

นี่เป็นการประมาณแบนด์วิดท์ที่มีประสิทธิภาพเป็น Mbits ต่อวินาที เบราว์เซอร์ทำให้การประเมินนี้จากปริมาณงานของแอปพลิเคชันที่สังเกตเห็นเมื่อเร็ว ๆ นี้ผ่านการเชื่อมต่อที่ใช้งานล่าสุด ความได้เปรียบที่ยิ่งใหญ่ที่สุดของวิธีนี้คือคุณไม่จำเป็นต้องดาวน์โหลดเนื้อหาใด ๆ เพียงเพื่อการคำนวณแบนด์วิดท์ / ความเร็ว

คุณสามารถดูคุณลักษณะนี้และคุณลักษณะอื่น ๆ ที่เกี่ยวข้องได้ที่นี่

เนื่องจากมันเป็นการสนับสนุนที่ จำกัด และการใช้งานที่แตกต่างกันเบราว์เซอร์ (เหมือนพฤศจิกายน 2017) จะขอแนะนำอ่านนี้ในรายละเอียด


18
นั่นคือสีแดงจำนวนมากในฉันสามารถใช้!
Francisco Presencia

2
ฉันไม่ได้รับตัวเลขที่สูงกว่า 10MBit เมื่อใช้สิ่งนี้ มีข้อ จำกัด หรือไม่?
Tobi

@Tobi ฉันยังดูเหมือนจะไม่ได้รับสูงกว่า 10Mbit ควรจะเป็นมากขึ้นเช่น 100Mbit
camjocotem

downlink คืออะไร มันคือความเร็วในการดาวน์โหลดหรือเปล่า?
gacat

@Tobi ฉันทั้งถ้าความเร็วมากกว่า 10Mb ฉันอ่าน 10
Aramil

21

ตามที่ฉันร่างในคำตอบอื่น ๆ ที่นี่ใน StackOverflowคุณสามารถทำได้โดยการกำหนดเวลาการดาวน์โหลดไฟล์ที่มีขนาดต่าง ๆ (เริ่มเล็ก ๆ ทางลาดขึ้นถ้าการเชื่อมต่อดูเหมือนว่าจะอนุญาต) ให้มั่นใจผ่านส่วนหัวของแคชและไฟล์นั้นเป็นจริง กำลังอ่านจากเซิร์ฟเวอร์ระยะไกลและไม่ได้รับจากแคช คุณไม่จำเป็นต้องมีเซิร์ฟเวอร์ของตัวเอง (ไฟล์อาจมาจากS3หรือที่คล้ายกัน) แต่คุณจะต้องมีที่อื่นเพื่อรับไฟล์เพื่อทดสอบความเร็วในการเชื่อมต่อ

ที่กล่าวว่าการทดสอบแบนด์วิดท์ในเวลานั้นไม่น่าเชื่อถืออย่างมากเนื่องจากเป็นผลกระทบจากการดาวน์โหลดรายการอื่น ๆ ในหน้าต่างอื่นความเร็วของเซิร์ฟเวอร์ลิงก์ระหว่างทาง ฯลฯ เป็นต้น แต่คุณสามารถเข้าใจได้ ใช้เทคนิคประเภทนี้


1
@Jakub: คุณต้องมีที่สำหรับอัปโหลด แต่ไม่มีเหตุผลที่คุณไม่สามารถใช้เทคนิคเดียวกันกับสิ่งนั้นได้ คุณสามารถใช้ข้อมูลที่คุณสร้างขึ้นทันทีหรือแน่นอนคุณสามารถใช้ข้อมูลบางส่วนที่คุณดาวน์โหลดมาใหม่สำหรับการทดสอบการดาวน์โหลด
TJ Crowder

ดังนั้นคุณจะรู้ได้อย่างไรว่าการอัปโหลดเสร็จสมบูรณ์เมื่อใด
Jakub Hampl

2
@Jakub: หลายวิธี หากคุณทำการส่งแบบฟอร์มไปยังที่ซ่อนiframeตัวอย่างเช่นคุณสำรวจiframeหรือหรือคุกกี้ให้เสร็จ หากคุณใช้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
คำตอบที่น่าเชื่อถือที่สุดในกรณีของฉัน
Abdalla Arbab

1
สิ่งที่เกี่ยวกับการทดสอบการอัปโหลด?
gumuruh

9

กลลวงของภาพนั้นเจ๋ง แต่ในการทดสอบของฉันมันกำลังโหลดก่อนที่ ajax จะโทรหาฉันอยากจะทำให้เสร็จ

ทางออกที่เหมาะสมในปี 2560 คือการใช้พนักงาน ( 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 = "blob" (ประเภท MIME ไม่ถูกต้อง), request.response.sizeสำหรับ ขนาดการดาวน์โหลดและ1000000สำหรับการคำนวณความเร็ว (เพราะ Mbps ควรอยู่ในหน่วย SI)
Rupert Rawnsley

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.