Search code examples
javascriptxmlhttprequest

Best method to save an XMLHttpRequest() to variable


What is the best method to save a XMLHttpRequest to a variable to use in a if statement. I'm trying to get the image size and depending on the size do something.

** *Please note that I'm using a random image from the internet for this question. I'm currently testing using a local server * **

This is what I have tried so far:

function get_image_size(imgurl) {
  var xhr = new XMLHttpRequest();
  let x
  xhr.open('HEAD', imgurl, true);
  xhr.onreadystatechange = function () {
    if (xhr.readyState == 4) {
      if (xhr.status == 200) {
        x = xhr.getResponseHeader('Content-Length');
        console.log(xhr.getResponseHeader('Content-Length')) // This works! returns bytes
      } else {
        console.log('ERROR');
      }
    }
  };
  xhr.send(null);
  console.log(x) // This doesn't work
  return x // This doesnt return anything
}

let image_size = get_image_size("https://images.ctfassets.net/hrltx12pl8hq/7yQR5uJhwEkRfjwMFJ7bUK/dc52a0913e8ff8b5c276177890eb0129/offset_comp_772626-opt.jpg?fit=fill&w=800&h=300")
// image_size returns "undifined"

I've also tried:

function get_filesize(url, callback) {
  var xhr = new XMLHttpRequest();
  xhr.open("HEAD", url, true);
  xhr.onreadystatechange = function() {
      if (this.readyState == this.DONE) {
          callback(parseInt(xhr.getResponseHeader("Content-Length")));
      }
  };
  xhr.send();
}

get_filesize("https://images.ctfassets.net/hrltx12pl8hq/7yQR5uJhwEkRfjwMFJ7bUK/dc52a0913e8ff8b5c276177890eb0129/offset_comp_772626-opt.jpg?fit=fill&w=800&h=300", function(size){image_size = size})

But still no luck.


Solution

  • You're making an asynchronous request, therefore, you can't have the value you need immediately assigned to x for use, your code needs a way to await the request before you can use or return x;

    One approach is to wrap your get_image_size function in a Promise like this

    function get_image_size(imgurl) {
      return new Promise((resolve,  reject) => {
          var xhr = new XMLHttpRequest();
          xhr.open('HEAD', imgurl, true);
          xhr.onreadystatechange = function () {
            if (xhr.readyState == 4) {
              if (xhr.status == 200) {
                resolve(xhr.getResponseHeader('Content-Length'))
              } else {
                console.log('ERROR');
              }
            }
          };
          xhr.send(null);
      })
    }
    
    

    and use it like this

    const IMAGE_URL = "https://images.ctfassets.net/hrltx12pl8hq/7yQR5uJhwEkRfjwMFJ7bUK/dc52a0913e8ff8b5c276177890eb0129/offset_comp_772626-opt.jpg?fit=fill&w=800&h=300";
    
    get_image_size(IMAGE_URL).then((size) => {
       console.log(size)
       // YOU CAN ONLY USE SIZE HERE.
       // NOT OUTSIDE OR REASSIGNED
       // COS IT MAY NOT BE AVAILABLE AS THIS IS AN ASYNCHRONOUS OPERATION
    })
    

    You can only use the value of size inside the callback of the chained .then() method.

    It will NOT work if you reassign or try to access it from outside, as it may not be available at the time your code executes.

    Another approach is to use the callback function, which I see you have tried, but the problem is that you were reassigning it like this image_size = size.

    You can only use it within that callback function.

    So technically you need to wrap all the code that needs the image-size inside that callback.