Revisited = image.onload NOT called
Asked Answered
I

1

6

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

Interpretative answered 28/7, 2015 at 3:3 Comment(2)
The example code snippets below work for me in Chrome, Firefox, and Safari.Marmalade
No problem! Glad I could help out :)Marmalade
M
4

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>
Marmalade answered 28/7, 2015 at 3:58 Comment(3)
Curious thing ... since you mentioned Chrome, I decided to download this Google Browser and test my .html locally on it. Chrome accessed the .onerror Event Handler of my original code and Safari never did??? Another curious observation ... using Chrome, alert(msg) inside .onerror Handler produced "undefined". SO, my challenge will be to figure out why the error is triggered.Interpretative
I would stick with a modern evergreen browser like Chrome for development. Once it's working in Chrome, then worry about other browsers. If Chrome gets to .onerror, it sounds like your image is bad. Try using the one above from Wikipedia. Also make use of the console in Chrome and the debugger keyword. This will allow you to step through your code and find where it's failing exactly.Marmalade
log('end time: %s', endTime);Adjust

© 2022 - 2024 — McMap. All rights reserved.