2

I am just learning about callbacks in javascript and wanted some help with the following code:

(please read entire post: I realise that exists is not set).

       window.addEventListener('load', function(){

    for (let count = 1; count <= 10; count++) {
        var toTest = "pic" + count + "a.jpg";
        var exists;
       imageExists(toTest, function(response){ if(response == true){ console.log("true" + count); exists = true;  } else { console.log("false" + count );  exists = false;}});
       console.log(exists);

       if(!exists){break;}

    }
    });

function imageExists(image_url, callback){
    console.log("processing: " + image_url);
    var http = new XMLHttpRequest();

        http.open('HEAD', image_url, true);
        http.send();
        http.onload = function() {
            console.log(http.status);
            if (http.status != 404)  {
                console.log(image_url + " exists (in imageExists)");
                callback(true);
            } else {
                console.error(image_url + "does not exist (in imageExists)");
                callback(false);
            }
        }

    }

Of course this doesn't work because it is checking exists variable before the callback. I tried replacing exists = false; with break but this this was illegal.

Any solutions to get the callback out of the function without completely changing the code?

Console log is:

processing: pic1a.jpg
app.js:14 undefined
app.js:56 200
app.js:58 pic1a.jpg exists (in imageExists)
app.js:13 true1
Atrag
  • 653
  • 2
  • 8
  • 29
  • Possible duplicate of [Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference](https://stackoverflow.com/questions/23667086/why-is-my-variable-unaltered-after-i-modify-it-inside-of-a-function-asynchron) – Sebastian Simon Mar 23 '18 at 02:30
  • 2
    My suggestion is to learn how to express yourself in a purely functional world, rather than this quasi-functional, quasi-procedural world which you seem trapped in. It's easier to convert functional code to procedural code than it is to convert procedural code to functional code (essentially what you're going to be doing)... It's just easier to refactor in functional form. To reiterate: You likely shouldn't use `break` because `break` is a procedural idiom which can't elegantly extend its effects beyond the functional idiom you've used here. – autistic Mar 23 '18 at 02:51

4 Answers4

1

This is a pretty common case that we should use promise and async/await for. This approach is also the way that takes the smallest effort in terms of refactoring your existing code. You can turn imageExists() into a function that returns a promise object, then it'll be able to be used as:

result = await imageExists(imgUrl);

instead of:

imageExists(imgUrl, callback(result) => {...});

Want to learn more advanced skills, please check out ReactiveX libray.

Johann Chang
  • 1,281
  • 2
  • 14
  • 25
0

A simple enough solution would be to convert the listener to an async function, convert imageExists into a Promise, and await it:

window.addEventListener('load', async function() {
  for (let count = 1; count <= 10; count++) {
    const toTest = "pic" + count + "a.jpg";
    const response = await imageExists(toTest);
    const exists = response.ok;
    if (!exists) {
      console.log('does not exist');
      break;
    }
  }
}

function imageExists(image_url) {
  console.log("processing: " + image_url);
  return fetch(image_url, { method: 'HEAD' });
}
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • Thank you. I see "await" and "promise" a few topics down in my tutorial. I guess I jumped the gun trying to do this without knowing them. – Atrag Mar 23 '18 at 02:37
0

so, I think:

function imageExists(image_url, callback) {
    console.log("processing: " + image_url);
    var img = document.createElement("IMG");
    img.load = function() { callback(true); };
    img.error = function() { callback(false); };
    img.src = image_url;
    }
Cuong Do
  • 29
  • 3
0

You're mixing synchronous/asynchronous code. You'll want to perform the looping logic with recursion. For example:

function imageExists(a,b){
    if(a>b){
        //found all images, we're done
        return;
    }else{
        var image_url = "pic"+a+"a.jpg";
        console.log("processing: " + image_url);
        var http = new XMLHttpRequest();
        http.open('HEAD', image_url, true);
        http.send();
        http.onload = function() {
            console.log(http.status);
            if (http.status != 404)  {
                console.log(image_url + " exists (in imageExists)");
                //image exists, let's check the next one...
                imageExists(a+1,b)
            } else {
                console.error(image_url + "does not exist (in imageExists)");
                //couldn't find image, stopping early (break)
                return;
            }
        }
    }
}

To check the existence of images 1-10 you'd simply call imageExists(1,10)

ReallyMadeMeThink
  • 1,061
  • 7
  • 11