Question

I'm having problems to use the value which I obtain when I call getResponseHeader on my Greasemonkey script.

First of all, I have declared the following global variables:

size = 0;
maxS = 153600; // Max. size (bytes).

Once the website has been completely loaded, my main function is called and inside of it I get all images within a certain div (which is not shown here because it's not relevant):

function main() {
    ...
    var imgs = posts[i].getElementsByTagName('img');
    for (var j = 0; j < imgs.length; ++j) {
        getFileSize(imgs[j].src, responseHandler);
        if (size > maxS)
            // Do something
    }
    ...
}

And this is how getFileSize works:

var getFileSize = function(address, responseHandler) {
    var req = new XMLHttpRequest();
    req.open('head', address, true);
    req.onreadystatechange = responseHandler;
    req.send(null);
};

var responseHandler = function(resp) {
    if (this.readyState == 1)
    this.abort();
    size = this.getResponseHeader("Content-length");
};

The problem is that even though if I check the value of size after the sentence

size = this.getResponseHeader("Content-length");

the value is the one I expect, in the main function its value is still 0 when it reaches this part of the code:

if (size > maxS)
    // Do something

I tried to figure out the answer by checking some other questions which I found in this website and I guess it has something to do with synchronization but I don't really know how to fix this issue.

Was it helpful?

Solution

The images are all on the exact same server, right? XMLHttpRequest() will not do cross-domain requests (without some new hoops that don't apply in a Greasemonkey context, anyway).

There are a few problems with that code:

  1. It expects size to be set synchronously but calls XMLHttpRequest() asynchronously.
  2. It aborts the request! And too soon. There is no good reason to abort a HEAD request.
  3. It uses a "magic number" in an obscuring way. Use the proper enumerated constant, when available. EG this.readyState == 1 is bad. this.readyState == this.OPENED is better.

For synchronous operation, change getFileSize(). Call it like so:

getFileSize (imgs[j].src);

Define it like so:

function getFileSize (address) {
    var request = new XMLHttpRequest();  
    request.open ('HEAD', address, false);  //-- false = Synchronous
    request.send (null);  

    size        = -666; // Error, or AJAX fail.
    if (request.status === 200) {  
        size    = request.getResponseHeader ("Content-length");
    }  
}



Notes:

  1. For performance and user-friendliness reasons, it would be better to refactor the approach to use asynchronous AJAX. But that's another question and less intuitive.
  2. If the images are cross-domain, you will need to use GM_xmlhttpRequest() -- which operates slightly differently and does not work properly for synchronous AJAX (last I checked -- which was a couple months ago).
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top