22

I have a JS function where a value is computed and this value should be returned but I get everytime undefined but if I console.log() the result within this function it works. Could you help?

function detect(URL) {
    var image = new Image();
    image.src = URL;
    image.onload = function() {
        var result = [{ x: 45, y: 56 }]; // An example result
        return result; // Doesn't work
    }
}

alert(detect('image.png'));
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Poru
  • 8,254
  • 22
  • 65
  • 89
  • 8
    Note: you also should set the `.onload` handler before you set `.src` because `onload` can trigger immediately when you set `.src` if the image is in the browser cache. If you set `.onload` afterwards, it may miss the load event and never fire. – jfriend00 Sep 15 '11 at 16:57
  • A) you need to set src AFTER load event listener definition B) You want **asynchronous behavior** - use Promises https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise or a sweeter version - Asynchronous Functions https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function – jave.web Oct 07 '19 at 19:16
  • Does this answer your question? [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – Liam Jul 08 '20 at 07:41

5 Answers5

44

The value is returned, but not from the detect function.

If you use a named function for the load event handler instead of an anonymous function, it's clearer what's happening:

function handleLoad() {
  var result = [{ x: 45, y: 56 }];
  return result;
}

function detect(URL) {
  var image = new Image();
  image.src = URL;
  image.onload = handleLoad;
}

The value is returned from the handleLoad function to the code that calls the event handler, but the detect function has already exited before that. There isn't even any return statement in the detect function at all, so you can't expect the result to be anything but undefined.

One common way of handling asynchronous scenarios like this, is to use a callback function:

function detect(URL, callback) {
  var image = new Image();
  image.src = URL;
  image.onload = function() {
    var result = [{ x: 45, y: 56 }];
    callback(result);
  };
}

You call the detect function with a callback, which will be called once the value is available:

detect('image.png', function(result){
  alert(result);
});
Guffa
  • 687,336
  • 108
  • 737
  • 1,005
  • yes, callback would be one of the better ways to handle this. – Web User Jul 07 '16 at 16:37
  • Hi, is it possible to use `async/await` instead of `callback` function? I've tried it in my code but got an error saying `Uncaught (in promise) Error: TypeError: callback is not a function`. The error is thrown because when I call my function I don't specify a `callback` but just have `const x = detect(URL)` (I'm using `detect function just to illustrate) – Le garcon Feb 13 '18 at 18:38
  • @IvanPrizov: The 'async/await' approach is pretty new, so it's not supported in older browsers. I would rather suggest that you return a promise from the function if you don't want to send in a callback function. – Guffa Feb 18 '18 at 03:36
  • @Guffa how can I return the `result` of callback from `detect` function? – Harshal Jan 22 '20 at 06:00
  • @HarshalMahajan: You can't. The `detect` function finishes before the callback is called. You can return a promise from the `detect` function, but that is basically just a wrapper around a callback. – Guffa Feb 23 '20 at 23:24
5

This is because the function detect doesn't return anything since the load event happens after the function is finished. And you forgot to append the image to something so it never loads.

You could do something like:

function detect(URL) {
    var image = new Image();
    image.src = URL;
    image.onload = function() {
        var result = 'result'; // An example result
        alert(result); // Doesn't work
    }
    document.body.appendChild(image)
}

detect('http://www.roseindia.net/javascript/appendChild-1.gif');

fiddle here http://jsfiddle.net/LVRuQ/

Nicola Peluchetti
  • 76,206
  • 31
  • 145
  • 192
4

I get it myself:

I didn't know that I can assign a variable to that (for me looking already assigned) onload.

function detect(URL) {
    var image = new Image();
    image.src = URL;
    var x = image.onload = function() {
        var result = [{ x: 45, y: 56 }]; // An example result
        return result;
    }();
    return x;
}

alert(detect('x'));
Poru
  • 8,254
  • 22
  • 65
  • 89
  • 10
    This does not make much sense. You execute the function, then set the result to `image.onload`. So `image.onload` will be an array, whilst it should be a function. Then you also set that array to `x` and return it. You do get the array back from `detect(...)`, but the whole idea of `onload` is lost. – pimvdb Sep 15 '11 at 17:10
  • 2
    as the above comment, this onload function doesn't work as it should be. you just execute the function manually which mean you don't need `image.onload` there. `image.onload` value is a function so it will automatically be executed when dom image is loading the image from its source. – Darryl RN Jul 28 '20 at 06:28
2

detect() doesn't return any value. If you want to get an alert, replace return result; by alert(result).

An analysis of your code:

function detect(URL) {
    ...
    image.onload = function(){ //assigning an event handler (function) to an object
        ...
        return result; //this return statement is called from within another function
    }
}//function "detect" ends here. No return statement has been encountered
Rob W
  • 341,306
  • 83
  • 791
  • 678
1

Your function detect doesn't return anything, which is why the alert is showing "undefined". The return statement that you claim doesn't work is returning from the anonymous function you assign to image.onload, and probably works fine if you would call that function.

Anomie
  • 92,546
  • 13
  • 126
  • 145
  • Yes, but if he doesn't add the image to the DOM the image never loads and the event is never fired – Nicola Peluchetti Sep 15 '11 at 16:45
  • @NicolaPeluchetti: True, but that's not the question here, and `onload` probably ignores the return value anyway. If he would somehow call that function manually, the return *would* work. – Anomie Sep 15 '11 at 16:46