From 3f99127b698d71932b5fa0f1cd66a1cc7b1660c7 Mon Sep 17 00:00:00 2001 From: dosse91 Date: Sun, 9 Oct 2016 09:13:36 +0200 Subject: [PATCH] Rewritten to use Web Workers; Easier to use; Added more examples --- README.md | 8 +-- example.html | 47 ----------------- example1.html | 26 ++++++++++ example2.html | 70 +++++++++++++++++++++++++ example3.html | 97 ++++++++++++++++++++++++++++++++++ speedtest.js | 123 -------------------------------------------- speedtest_worker.js | 104 +++++++++++++++++++++++++++++++++++++ 7 files changed, 301 insertions(+), 174 deletions(-) delete mode 100644 example.html create mode 100644 example1.html create mode 100644 example2.html create mode 100644 example3.html delete mode 100644 speedtest.js create mode 100644 speedtest_worker.js diff --git a/README.md b/README.md index 7a154d4..f826057 100644 --- a/README.md +++ b/README.md @@ -2,23 +2,23 @@ No Flash, No Java, No Websocket, No Bullshit. -This is a very small (4k) Speedtest implemented in Javascript, that relies only on XMLHttpRequest. +This is a very small (4k) Speedtest implemented in Javascript, using XMLHttpRequest and Web Workers. ## Try it [Take a Speedtest](http://speedtest.adolfintel.com) ## Compatibility -Microsoft Edge, Firefox 10+, Chrome 10+, Opera 15+, Safari 7 (not tested) +Only modern browsers are supported (Edge 12+) ## Requirements - - A reasonably fast web serve + - A reasonably fast web server - Some way to generate garbage data using either the included PHP script, a [big file of random data](http://downloads.adolfintel.com/geth.php?r=speedtest-bigfile), or a symlink to /dev/urandom - Your server must not compress the data it sends - Your server must accept large POST requests (up to 10 Megabytes), otherwise the upload test will fail - Client side, there must not be any type of buffering (such as a proxy), or you may get incorrect results ## How to use -See example.html, it's not rocket science. +See the examples, it's really simple. ## License Copyright (C) 2016 Federico Dossena diff --git a/example.html b/example.html deleted file mode 100644 index 507b898..0000000 --- a/example.html +++ /dev/null @@ -1,47 +0,0 @@ - - - -Speedtest - - - -

Speedtest

-

Download

-
Wait...
-

Upload

-
Wait...
-

Latency

-
Wait...
- - - \ No newline at end of file diff --git a/example1.html b/example1.html new file mode 100644 index 0000000..a8c2842 --- /dev/null +++ b/example1.html @@ -0,0 +1,26 @@ + + + +Speedtest + + +

Speedtest

+

Download

+
+

Upload

+
+

Latency

+
+ + + \ No newline at end of file diff --git a/example2.html b/example2.html new file mode 100644 index 0000000..be1a907 --- /dev/null +++ b/example2.html @@ -0,0 +1,70 @@ + + + +Speedtest + + + +

Speedtest

+
+
Download
+
  
+
Mbit/s
+
+
+
Upload
+
  
+
Mbit/s
+
+
+
Latency
+
  
+
ms
+
+ + + \ No newline at end of file diff --git a/example3.html b/example3.html new file mode 100644 index 0000000..9ee0a41 --- /dev/null +++ b/example3.html @@ -0,0 +1,97 @@ + + + +Speedtest + + + + +

Speedtest

+ +Run speedtest + + \ No newline at end of file diff --git a/speedtest.js b/speedtest.js deleted file mode 100644 index ce93259..0000000 --- a/speedtest.js +++ /dev/null @@ -1,123 +0,0 @@ -function DownloadTester(serverURL,done,update,err){ - this.xhr=new XMLHttpRequest(); - this.firstTick=true; - this.prevLoaded=0; - this.startT=new Date().getTime(); - this.prevT=new Date().getTime(); - this.speed=0.0; - if(done)this.onDone=done; if(update)this.onUpdate=update; if(err)this.onFail=err; - this.xhr.onprogress=function(event){ - var instspd=(event.loaded-this.prevLoaded)/((new Date().getTime()-this.prevT)/1000.0); - if(isNaN(instspd)||!isFinite(instspd)) return; - if(this.firstTick){ - this.speed=instspd; - this.firstTick=false; - }else{ - this.speed=this.speed*0.9+instspd*0.1; - } - this.prevLoaded=event.loaded; - this.prevT=new Date().getTime(); - this.onUpdate(); - if(((this.prevT-this.startT)/1000.0)>15){try{this.xhr.abort();}catch(e){} this.onDone();} - }.bind(this); - this.xhr.onload=function(){ - this.onUpdate(); - this.onDone(); - }.bind(this); - this.xhr.onerror=function(){ - this.onUpdate(); - this.onFail(); - }.bind(this); - this.xhr.open("GET", serverURL+"?random="+Math.random(),true); - this.xhr.send(); -} -DownloadTester.prototype={ - constructor:DownloadTester, - onDone:function(){}, - onFail:function(){}, - onUpdate:function(){}, - getValue:function(){return ((this.speed*8)/1048576.0).toFixed(2);}, - cancel:function(){try{this.xhr.abort();}catch(e){}} -} - -function UploadTester(serverURL,done,update,err){ - this.xhr=new XMLHttpRequest(); - this.firstTick=true; - this.prevLoaded=0; - this.startT=new Date().getTime(); - this.prevT=new Date().getTime(); - this.speed=0.0; - if(done)this.onDone=done; if(update)this.onUpdate=update; if(err)this.onFail=err; - this.xhr.upload.onprogress=function(event){ - var instspd=(event.loaded-this.prevLoaded)/((new Date().getTime()-this.prevT)/1000.0); - if(isNaN(instspd)||!isFinite(instspd)) return; - if(this.firstTick){ - this.firstTick=false; - }else{ - this.speed=this.speed*0.7+instspd*0.3; - } - this.prevLoaded=event.loaded; - this.prevT=new Date().getTime(); - this.onUpdate(); - if(((this.prevT-this.startT)/1000.0)>15){try{this.xhr.abort();}catch(e){} this.onDone();} - }.bind(this); - this.xhr.onload=function(){ - this.onUpdate(); - this.onDone(); - }.bind(this); - this.xhr.onerror=function(){ - this.onUpdate(); - this.onFail(); - }.bind(this); - this.xhr.open("POST", serverURL+"?random="+Math.random(),true); - this.xhr.send(new ArrayBuffer(10485760)); -} -UploadTester.prototype={ - constructor:UploadTester, - onDone:function(){}, - onFail:function(){}, - onUpdate:function(){}, - getValue:function(){return ((this.speed*8)/1048576.0).toFixed(2);}, - cancel:function(){try{this.xhr.abort();}catch(e){}} -} - -function PingTester(serverURL,done,update,err){ - this.xhr=null; - this.prevT=null; - this.ping=0.0; - this.i=0; - this.pingURL=serverURL; - if(done)this.onDone=done; - if(update)this.onUpdate=update; - if(err)this.onFail=err; - this.doPing=function(){ - this.prevT=new Date().getTime(); - this.xhr=new XMLHttpRequest(); - this.xhr.onload=function(){ - if(this.i==0){ - this.prevT=new Date().getTime(); - }else{ - var instspd=new Date().getTime()-this.prevT; - if(this.i==1) this.ping=instspd; else this.ping=this.ping*0.9+instspd*0.1; - } - this.onUpdate(); - this.i++; - if(this.i<50) this.doPing(); else this.onDone(); - }.bind(this); - this.xhr.onerror=function(){ - this.onUpdate(); - this.onFail(); - }.bind(this); - this.xhr.open("GET", this.pingURL+"?random="+Math.random(),true); - this.xhr.send(); - }.bind(this); - this.doPing(); -} -PingTester.prototype={ - constructor:PingTester, - onDone:function(){}, - onFail:function(){}, - onUpdate:function(){}, - getValue:function(){return this.ping.toFixed(2);}, - cancel:function(){this.i=9999; if(this.xhr) try{xhr.abort();}catch(e){}} -} \ No newline at end of file diff --git a/speedtest_worker.js b/speedtest_worker.js new file mode 100644 index 0000000..3ccea6e --- /dev/null +++ b/speedtest_worker.js @@ -0,0 +1,104 @@ +var testStatus=0,dlStatus="",ulStatus="",pingStatus=""; +var xhr=null; +this.addEventListener('message', function(e){ + var params=e.data.split(" "); + if(params[0]=="status"){ + postMessage(testStatus+";"+dlStatus+";"+ulStatus+";"+pingStatus); + } + if(params[0]=="start"){ + if(testStatus==0){ + testStatus=1; + var dlUrl=params[1]?params[1]:"garbage.php", ulUrl=params[2]?params[2]:"empty.dat", pingUrl=params[3]?params[3]:"empty.dat"; + dlTest(dlUrl,function(){testStatus=2;ulTest(ulUrl,function(){testStatus=3;pingTest(pingUrl,function(){testStatus=4;});});}); + } + } + if(params[0]=="abort"){ + try{if(xhr)xhr.abort();}catch(e){} + testStatus=5;dlStatus="";ulStatus="";pingStatus=""; + } +}); + +function dlTest(serverURL,done){ + var firstTick=true,startT=new Date().getTime(), prevT=new Date().getTime(),prevLoaded=0,speed=0.0; + xhr=new XMLHttpRequest(); + xhr.onprogress=function(event){ + var instspd=(event.loaded-prevLoaded)/((new Date().getTime()-prevT)/1000.0); + if(isNaN(instspd)||!isFinite(instspd)) return; + if(firstTick){ + speed=instspd; + firstTick=false; + }else{ + speed=speed*0.9+instspd*0.1; + } + prevLoaded=event.loaded; + prevT=new Date().getTime(); + dlStatus=((speed*8)/1048576.0).toFixed(2); + if(((prevT-startT)/1000.0)>15){try{xhr.abort();}catch(e){} xhr=null; done();} + }.bind(this); + xhr.onload=function(){ + dlStatus=((speed*8)/1048576.0).toFixed(2); + xhr=null; + done(); + }.bind(this); + xhr.onerror=function(){ + dlStatus="Fail"; + xhr=null; + done(); + }.bind(this); + xhr.open("GET", serverURL+"?random="+Math.random(),true); + xhr.send(); +} + +function ulTest(serverURL,done){ + var firstTick=true,startT=new Date().getTime(), prevT=new Date().getTime(),prevLoaded=0,speed=0.0; + xhr=new XMLHttpRequest(); + xhr.upload.onprogress=function(event){ + var instspd=(event.loaded-prevLoaded)/((new Date().getTime()-prevT)/1000.0); + if(isNaN(instspd)||!isFinite(instspd)) return; + if(firstTick){ + firstTick=false; + }else{ + speed=speed*0.7+instspd*0.3; + } + prevLoaded=event.loaded; + prevT=new Date().getTime(); + ulStatus=((speed*8)/1048576.0).toFixed(2); + if(((prevT-startT)/1000.0)>15){try{xhr.abort();}catch(e){} xhr=null; done();} + }.bind(this); + xhr.onload=function(){ + ulStatus=((speed*8)/1048576.0).toFixed(2); + done(); + }.bind(this); + xhr.onerror=function(){ + ulStatus="Fail"; + done(); + }.bind(this); + xhr.open("POST", serverURL+"?random="+Math.random(),true); + xhr.send(new ArrayBuffer(10485760)); +} + +function pingTest(pingUrl,done){ + var prevT=null,ping=0.0,i=0; + var doPing=function(){ + prevT=new Date().getTime(); + xhr=new XMLHttpRequest(); + xhr.onload=function(){ + if(i==0){ + prevT=new Date().getTime(); + }else{ + var instspd=new Date().getTime()-prevT; + if(i==1) ping=instspd; else ping=ping*0.9+instspd*0.1; + } + pingStatus=ping.toFixed(2); + i++; + if(i<50) doPing(); else done(); + }.bind(this); + xhr.onerror=function(){ + pingStatus="Fail"; + done(); + }.bind(this); + xhr.open("GET", pingUrl+"?random="+Math.random(),true); + xhr.send(); + }.bind(this); + doPing(); +}