Reputation:
Very old, but very UNsolved subject: image.onload
not called.
Code tells the story better than words ...
Calling .html =
<script>
var newConnection = new MeasureConnectionSpeed();
if (newConnection.isHighSpeed())
doSomething1;
else
doSomething2;
</script>
Called .html =
<script>
function MeasureConnectionSpeed() {
var connection = this;
var imgDownloadSrc = "http://someLargeImage.jpg";
var imgDownloadSize = 943 * 1024; // bytes
var startTime = 0,
endTime = 0; // set later
connection.isHighSpeedConnection = false; // = a Object Property
// an Object Method ...
// just the function declaration which is called via
// connection.computeResults()
connection.isHighSpeed = isHighSpeed;
connection.computeResults = computeResults; // another Object Method
var testImgDownload = new Image();
testImgDownload.onload = function () {
endTime = (new Date()).getTime();
connection.computeResults();
} // testImgDownload.onload
testImgDownload.onerror = function (err, msg) {
alert("Invalid image, or error downloading");
}
// We immediately continue while testImgDownload is still loading ...
// the timer is started here and ended inside testImgDownload.onload
startTime = (new Date()).getTime();
// This forces an attempt to download the testImgDownload and get the
// measurements withOUT actually downloading to your Cache:
var cacheBuster = "?nnn=" + startTime;
testImgDownload.src = imgDownloadSrc + cacheBuster;
function computeResults() {
var speedMbps = someNumber;
connection.isHighSpeedConnection = speedMbps > 20;
} // computeResults
// this.isHighSpeed() = isHighSpeed()
function isHighSpeed() {
return connection.isHighSpeedConnection;
}
} // MeasureConnectionSpeed
</script>
* EDIT #1 *
Two more bits ...
I decided to download Google's Chrome and test my .html locally on it. Chrome accessed the .onerror Event Handler of my original code. Safari and Firefox never did???
Another curious observation ... using Chrome, alert(err)
inside my .onerror Event Handler produced "undefined". But, I did use alert(this.width)
and alert(this.naturalWidth)
, each showing 0 ... which means it is an invalid image???
And the invalid image error even occurs if I place the src before the .onload
Handler.
That really is it for now!
* EDIT #2 - on August 8th, 2015 *
1) I am truly very sorry I have not returned earlier ... but I began to not feel well, so got a little more physical rest
2) Anyway, I implemented Dave Snyder's wonderful IIFE code and it definitely worked ... the code within the .onload Handler properly worked and I am truly extremely grateful to Dave and all the time he provided to little-ole-me. Of course, I dumped the newConnection = new MeasureConnectionSpeed() and used Dave's IIFE approach.
Now, all I have to figure out why this code is giving me about 5 Mbps speed numbers where I have 30 Mbps via my Ethernet Router. I would truly expect to see a number close.
I really, really hate to have to include another API since my whole purpose of speed measurement is to decide weather to redirect to a relatively "busy" site or to a "keep it simple" version.
Tons of thanks, Dave. You're my hero.
John Love
Upvotes: 6
Views: 1172
Reputation: 1033
This works for me in Chrome.
(function(){
var imgDownloadSrc = "https://upload.wikimedia.org/wikipedia/commons/d/d8/Schwalbenschwanz_%28Papilio_machaon%29.jpg",
testImgDownload = new Image(),
startTime, endTime,
stackOverflowLog = document.getElementById('log');
var log = function(message, str) {
stackOverflowLog.innerHTML += message.replace("%s", str) + "<br>";
console.log(message, str);
}
testImgDownload.onload = function () {
log('image loaded!');
endTime = +new Date();
log('end time: %s', startTime);
log('total time: %s', (endTime - startTime));
}
testImgDownload.onerror = function (err, msg) {
throw "Invalid image, or error downloading";
}
startTime = +new Date();
log('start time: %s', startTime);
testImgDownload.src = imgDownloadSrc + "?" + startTime;
log('downloading: %s', testImgDownload.src);
})();
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Untitled Document</title>
</head>
<body>
<pre id="log"></pre>
</body>
</html>
Here's your code, slightly modified so it runs. image.onload
seems to work fine, but isHighSpeed()
is called before the image has finished downloading. It will need to be refactored / reordered so that you call isHighSpeed()
after it's been set. It's common to use a callback for this kind of thing.
/* for illustration */
var stackOverflowLog = document.getElementById("log");
var log = function(message, str) {
stackOverflowLog.innerHTML += message.replace("%s", str) + "<br>";
console.log(message, str);
}
/* calling.html */
var newConnection = new MeasureConnectionSpeed();
log('newConnection.isHighSpeed()? %s', newConnection.isHighSpeed());
/* called.html */
function MeasureConnectionSpeed() {
var connection = this;
var imgDownloadSrc = "https://upload.wikimedia.org/wikipedia/commons/d/d8/Schwalbenschwanz_%28Papilio_machaon%29.jpg";
var imgDownloadSize = 1709360 * 8; // bits (~1.6mb * 8)
var startTime = 0,
endTime = 0; // set later
connection.isHighSpeedConnection = undefined; // = a Object Property
// an Object Method ...
// just the function declaration which is called via
// connection.computeResults()
connection.isHighSpeed = isHighSpeed;
connection.computeResults = computeResults; // another Object Method
var testImgDownload = new Image();
testImgDownload.onload = function () {
endTime = (new Date()).getTime();
log('endTime: %s', endTime);
connection.computeResults();
} // testImgDownload.onload
testImgDownload.onerror = function (err, msg) {
log("!!! ERROR Invalid image, or error downloading");
}
// We immediately continue while testImgDownload is still loading ...
// the timer is started here and ended inside testImgDownload.onload
startTime = (new Date()).getTime();
log('startTime: %s', startTime);
// This forces an attempt to download the testImgDownload and get the
// measurements withOUT actually downloading to your Cache:
var cacheBuster = "?nnn=" + startTime;
testImgDownload.src = imgDownloadSrc + cacheBuster;
log('loading: %s', testImgDownload.src);
function computeResults() {
var duration, speed, speedMbps;
duration = (endTime - startTime) / 1000; // seconds
speed = imgDownloadSize / duration; // bits per second
speedMbps = speed / 1000000; // megabits
log('duration: %s', duration);
log('speed: %s', speed);
log('speedMbps: %s', speedMbps);
connection.isHighSpeedConnection = speedMbps > 20;
} // computeResults
// this.isHighSpeed() = isHighSpeed()
function isHighSpeed() {
return connection.isHighSpeedConnection;
}
} // MeasureConnectionSpeed
<pre id="log"></pre>
Upvotes: 4