I have a function foo
which makes an Ajax request. How can I return the response from foo
?
I tried returning the value from the success
callback as well as assigning the response to a local variable inside the function and returning that one, but none of those ways actually return the response.
function foo() {
var result;
$.ajax({
url: '...',
success: function(response) {
result = response;
// return response; // <- I tried that one as well
}
});
return result;
}
var result = foo(); // It always ends up being `undefined`.
I will answer with a horrible-looking, hand-drawn comic. The second image is the reason why
result
isundefined
in your code example.Rather than throwing code at you, there are 2 concepts that are key to understanding how JS handles callbacks and asynchronicity. (is that even a word?)
The Event Loop and Concurrency Model
There are three things you need to be aware of; The queue; the event loop and the stack
In broad, simplistic terms, the event loop is like the project manager, it is constantly listening for any functions that want to run and communicates between the queue and the stack.
Once it receives a message to run something it adds it to the queue. The queue is the list of things that are waiting to execute (like your AJAX request). imagine it like this:
When one of these messages is going to execute it pops the message from the queue and creates a stack, the stack is everything JS needs to execute to perform the instruction in the message. So in our example it's being told to call
foobarFunc
So anything that foobarFunc needs to execute (in our case
anotherFunction
) will get pushed onto the stack. executed, and then forgotten about - the event loop will then move onto the next thing in the queue (or listen for messages)The key thing here is the order of execution. That is
WHEN is something going to run
When you make a call using AJAX to an external party or run any asynchronous code (a setTimeout for example), Javascript is dependant upon a response before it can proceed.
The big question is when will it get the response? The answer is we don't know - so the event loop is waiting for that message to say "hey run me". If JS just waited around for that message synchronously your app would freeze and it will suck. So JS carries on executing the next item in the queue whilst waiting for the message to get added back to the queue.
That's why with asynchronous functionality we use things called callbacks. It's kinda like a promise quite literally. As in I promise to return something at some point jQuery uses specific callbacks called
deffered.done
deffered.fail
anddeffered.always
(amongst others). You can see them all hereSo what you need to do is pass a function that is promised to execute at some point with data that is passed to it.
Because a callback is not executed immediately but at a later time it's important to pass the reference to the function not it executed. so
so most of the time (but not always) you'll pass
foo
notfoo()
Hopefully that will make some sense. When you encounter things like this that seem confusing - i highly recommend reading the documentation fully to at least get an understanding of it. It will make you a much better developer.
This is one of the places which two ways data binding or store concept that's used in many new JavaScript frameworks will work great for you...
So if you are using Angular, React or any other frameworks which do two ways data binding or store concept this issue is simply fixed for you, so in easy word, your result is
undefined
at the first stage, so you have gotresult = undefined
before you receive the data, then as soon as you get the result, it will be updated and get assigned to the new value which response of your Ajax call...But how you can do it in pure javascript or jQuery for example as you asked in this question?
You can use a callback, promise and recently observable to handle it for you, for example in promises we have some function like
success()
orthen()
which will be executed when your data is ready for you, same with callback or subscribe function on observable.For example in your case which you are using jQuery, you can do something like this:
For more information study about promises and observables which are newer ways to do this async stuffs.
It's a very common issue we face while struggling with the 'mysteries' of JavaScript. Let me try demystifying this mystery today.
Let's start with a simple JavaScript function:
That's a simple synchronous function call (where each line of code is 'finished with its job' before the next one in sequence), and the result is same as expected.
Now let's add a bit of twist, by introducing little delay in our function, so that all lines of code are not 'finished' in sequence. Thus, it will emulate the asynchronous behavior of function :
So there you go, that delay just broke the functionality we expected! But what exactly happened ? Well, it's actually pretty logical if you look at the code. the function
foo()
, upon execution, returns nothing (thus returned value isundefined
), but it does start a timer, which executes a function after 1s to return 'wohoo'. But as you can see, the value that's assigned to bar is the immediately returned stuff from foo(), not anything else that comes later.So, how do we tackle this issue?
Let's ask our function for a PROMISE. Promise is really about what it means : it means that the function guarantees you to provide with any output it gets in future. so let's see it in action for our little problem above :
Thus, the summary is - to tackle the asynchronous functions like ajax based calls etc., you can use a promise to
resolve
the value (which you intend to return). Thus, in short you resolve value instead of returning, in asynchronous functions.UPDATE (Promises with async/await)
Apart from using
then/catch
to work with promises, there exists one more approach. The idea is to recognize an asynchronous function and then wait for the promises to resolve, before moving to the next line of code. It's still just thepromises
under the hood, but with a different syntactical approach. To make things clearer, you can find a comparison below:then/catch version:
async/await version:
The question was:
which CAN be interpreted as:
The solution will be to avoid callbacks, and use a combination of Promises and async/await.
I would like to give an example for a Ajax request.
(Although it can be written in Javascript, I prefer to write it in Python, and compile it to Javascript using Transcrypt. It will be clear enough.)
Lets first enable JQuery usage, to have
$
available asS
:Define a function which returns a Promise, in this case an Ajax call:
Use the asynchronous code as if it were synchronous:
The simplest solution is create a JavaScript function and call it for the Ajax
success
callback.