I have a function foo which makes an Ajax request. How can I return the response from foo?

I tried to return the value from the success callback as well as assigning the response to a local variable inside the function and return 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`.
10 upvote
  flag
@MaximShoustin I've added a JavaScript only answer (no jQuery) but like Felix said - "How do I return the response from an AJAX call" is really a nice way to say "How does concurrency work in JavaScript". Not to mention Angular's $http is very similar to jQuery's $.ajax anyway with some minor differences (like interoping with the digest cycle). – Benjamin Gruenbaum
62 upvote
  flag
Do not use async: false. It will freeze the browser and drive users away. Read blog.slaks.net/2015-01-04/async-method-patterns to learn how to work with asynchronous operations. – SLaks
3 upvote
  flag
It is possible like You did this by ading async: false as attribute of first parameter. See my answer below. @tvanfosson gave this solution on Stackoverflow. – arrowman
1 upvote
  flag
1 upvote
  flag
@SLaks Someone please relay that to the website "rock star developers" at AirAsia.com. That's a great live case study (enhanced by the ajax calls taking a couple of seconds) of why never to use async: false. – Mâtt Frëëman
upvote
  flag
Can we rephrase the code to be less jquery-specific? Just some generic ajax function with a callback or a promise. Since this is a dupe-target #1 at the moment, I guess it would be helpful. – georg
upvote
  flag
@georg: there is nothing really jquery specific about it. I could rename $.ajax to ajax and claim that it's a generic Ajax function. But would that really make any difference? – Felix Kling
upvote
  flag
yes, ajax(url, function(response) would be definitely better. – georg

23 Answers 11

up vote 3867 down vote accepted

-> For a more general explanation of async behavior with different examples, please see Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference

-> If you already understand the problem, skip to the possible solutions below.

The problem

The A in Ajax stands for asynchronous . That means sending the request (or rather receiving the response) is taken out of the normal execution flow. In your example, $.ajax returns immediately and the next statement, return result;, is executed before the function you passed as success callback was even called.

Here is an analogy which hopefully makes the difference between synchronous and asynchronous flow clearer:

Synchronous

Imagine you make a phone call to a friend and ask him to look something up for you. Although it might take a while, you wait on the phone and stare into space, until your friend gives you the answer that you needed.

The same is happening when you make a function call containing "normal" code:

function findItem() {
    var item;
    while(item_not_found) {
        // search
    }
    return item;
}

var item = findItem();

// Do something with item
doSomethingElse();

Even though findItem might take a long time to execute, any code coming after var item = findItem(); has to wait until the function returns the result.

Asynchronous

You call your friend again for the same reason. But this time you tell him that you are in a hurry and he should call you back on your mobile phone. You hang up, leave the house and do whatever you planned to do. Once your friend calls you back, you are dealing with the information he gave to you.

That's exactly what's happening when you do an Ajax request.

findItem(function(item) {
    // Do something with item
});
doSomethingElse();

Instead of waiting for the response, the execution continues immediately and the statement after the Ajax call is executed. To get the response eventually, you provide a function to be called once the response was received, a callback (notice something? call back ?). Any statement coming after that call is executed before the callback is called.



Solution(s)

Embrace the asynchronous nature of JavaScript! While certain asynchronous operations provide synchronous counterparts (so does "Ajax"), it's generally discouraged to use them, especially in a browser context.

Why is it bad do you ask?

JavaScript runs in the UI thread of the browser and any long running process will lock the UI, making it unresponsive. Additionally, there is an upper limit on the execution time for JavaScript and the browser will ask the user whether to continue the execution or not.

All of this is really bad user experience. The user won't be able to tell whether everything is working fine or not. Furthermore, the effect will be worse for users with a slow connection.

In the following we will look at three different solutions that are all building on top of each other:

  • Promises with async/await (ES2017+, available in older browsers if you use a transpiler or regenerator)
  • Callbacks (popular in node)
  • Promises with then() (ES2015+, available in older browsers if you use one of the many promise libraries)

All three are available in current browsers, and node 7+.


ES2017+: Promises with async/await

The new ECMAScript version released in 2017 introduced syntax level support for asynchronous functions. With the help of async and await, you can write asynchronous in a "synchronous style". Make no mistake though: The code is still asynchronous, but it's easier to read/understand.

async/await builds on top of promises: an async function always returns a promise. await "unwraps" a promise and either result in the value the promise was resolved with or throws an error if the promise was rejected.

Important: You can only use await inside an async function. That means that at the very top level, you still have to work directly with the promise.

You can read more about async and await on MDN.

Here is an example that builds on top of delay above:

// Using 'superagent' which will return a promise.
var superagent = require('superagent')

// This is isn't declared as `async` because it already returns a promise
function delay() {
  // `delay` returns a promise
  return new Promise(function(resolve, reject) {
    // Only `delay` is able to resolve or reject the promise
    setTimeout(function() {
      resolve(42); // After 3 seconds, resolve the promise with value 42
    }, 3000);
  });
}


async function getAllBooks() {
  try {
    // GET a list of book IDs of the current user
    var bookIDs = await superagent.get('/user/books');
    // wait for a second (just for the sake of this example)
    await delay(1000);
    // GET information about each book
    return await superagent.get('/books/ids='+JSON.stringify(bookIDs));
  } catch(error) {
    // If any of the awaited promises was rejected, this catch block
    // would catch the rejection reason
    return null;
  }
}

// Async functions always return a promise
getAllBooks()
  .then(function(books) {
    console.log(books);
  });

Newer browser and node versions support async/await. You can also support older environments by transforming your code to ES5 with the help of regenerator (or tools that use regenerator, such as Babel).


Let functions accept callbacks

A callback is simply a function passed to another function. That other function can call the function passed whenever it is ready. In the context of an asynchronous process, the callback will be called whenever the asynchronous process is done. Usually, the result is passed to the callback.

In the example in the question, you can make foo accept a callback and use it as success callback. So this

var result = foo();
// Code that depends on 'result'

becomes

foo(function(result) {
    // Code that depends on 'result'
});

Here we defined the function "inline" but you can pass any function reference:

function myCallback(result) {
    // Code that depends on 'result'
}

foo(myCallback);

foo itself is defined as follows:

function foo(callback) {
    $.ajax({
        // ...
        success: callback
    });
}

callback will refer to the function we pass to foo when we call it and we simply pass it on to success. I.e. once the Ajax request is successful, $.ajax will call callback and pass the response to the callback (which can be referred to with result, since this is how we defined the callback).

You can also process the response before passing it to the callback:

function foo(callback) {
    $.ajax({
        // ...
        success: function(response) {
            // For example, filter the response
            callback(filtered_response);
        }
    });
}

It's easier to write code using callbacks than it may seem. After all, JavaScript in the browser is heavily event-driven (DOM events). Receiving the Ajax response is nothing else but an event.
Difficulties could arise when you have to work with third-party code, but most problems can be solved by just thinking through the application flow.


ES2015+: Promises with then()

The Promise API is a new feature of ECMAScript 6 (ES2015), but it has good browser support already. There are also many libraries which implement the standard Promises API and provide additional methods to ease the use and composition of asynchronous functions (e.g. bluebird).

Promises are containers for future values. When the promise receives the value (it is resolved) or when it is canceled (rejected), it notifies all of its "listeners" who want to access this value.

The advantage over plain callbacks is that they allow you to decouple your code and they are easier to compose.

Here is a simple example of using a promise:

function delay() {
  // `delay` returns a promise
  return new Promise(function(resolve, reject) {
    // Only `delay` is able to resolve or reject the promise
    setTimeout(function() {
      resolve(42); // After 3 seconds, resolve the promise with value 42
    }, 3000);
  });
}

delay()
  .then(function(v) { // `delay` returns a promise
    console.log(v); // Log the value once it is resolved
  })
  .catch(function(v) {
    // Or do something else if it is rejected 
    // (it would not happen in this example, since `reject` is not called).
  });

Applied to our Ajax call we could use promises like this:

function ajax(url) {
  return new Promise(function(resolve, reject) {
    var xhr = new XMLHttpRequest();
    xhr.onload = function() {
      resolve(this.responseText);
    };
    xhr.onerror = reject;
    xhr.open('GET', url);
    xhr.send();
  });
}

ajax("/echo/json")
  .then(function(result) {
    // Code depending on result
  })
  .catch(function() {
    // An error occurred
  });

Describing all the advantages that promise offer is beyond the scope of this answer, but if you write new code, you should seriously consider them. They provide a great abstraction and separation of your code.

More information about promises: HTML5 rocks - JavaScript Promises

Side note: jQuery's deferred objects

Deferred objects are jQuery's custom implementation of promises (before the Promise API was standardized). They behave almost like promises but expose a slightly different API.

Every Ajax method of jQuery already returns a "deferred object" (actually a promise of a deferred object) which you can just return from your function:

function ajax() {
    return $.ajax(...);
}

ajax().done(function(result) {
    // Code depending on result
}).fail(function() {
    // An error occurred
});

Side note: Promise gotchas

Keep in mind that promises and deferred objects are just containers for a future value, they are not the value itself. For example, suppose you had the following:

function checkPassword() {
    return $.ajax({
        url: '/password',
        data: {
            username: $('#username').val(),
            password: $('#password').val()
        },
        type: 'POST',
        dataType: 'json'
    });
}

if (checkPassword()) {
    // Tell the user they're logged in
}

This code misunderstands the above asynchrony issues. Specifically, $.ajax() doesn't freeze the code while it checks the '/password' page on your server - it sends a request to the server and while it waits, immediately returns a jQuery Ajax Deferred object, not the response from the server. That means the if statement is going to always get this Deferred object, treat it as true, and proceed as though the user is logged in. Not good.

But the fix is easy:

checkPassword()
.done(function(r) {
    if (r) {
        // Tell the user they're logged in
    } else {
        // Tell the user their password was bad
    }
})
.fail(function(x) {
    // Tell the user something bad happened
});


Not recommended: Synchronous "Ajax" calls

As I mentioned, some(!) asynchronous operations have synchronous counterparts. I don't advocate their use, but for completeness' sake, here is how you would perform a synchronous call:

Without jQuery

If you directly use a XMLHTTPRequest object, pass false as third argument to .open.

jQuery

If you use jQuery, you can set the async option to false. Note that this option is deprecated since jQuery 1.8. You can then either still use a success callback or access the responseText property of the jqXHR object:

function foo() {
    var jqXHR = $.ajax({
        //...
        async: false
    });
    return jqXHR.responseText;
}

If you use any other jQuery Ajax method, such as $.get, $.getJSON, etc., you have to change it to $.ajax (since you can only pass configuration parameters to $.ajax).

Heads up! It is not possible to make a synchronous JSONP request. JSONP by its very nature is always asynchronous (one more reason to not even consider this option).

37 upvote
  flag
@Pommy: If you want to use jQuery, you have to include it. Please refer to docs.jquery.com/Tutorials:Getting_Started_with_jQuery. – Felix Kling
1 upvote
  flag
In Solution 1, sub jQuery, I could not understand this line: If you use any other jQuery AJAX method, such as $.get, $.getJSON, etc., you have them to $.ajax. (Yes, I realize my nick is a tad ironic in this case) – gibberish
11 upvote
  flag
@gibberish: Mmmh, I don't know how it can be made clearer. Do you see how foo is called and a function is passed to it (foo(function(result) {....});)? result is used inside this function and is the response of the Ajax request. To refer to this function, the first parameter of foo is called callback and assigned to success instead of an anonymous function. So, $.ajax will call callback when the request was successful. I tried to explain it a bit more. – Felix Kling
20 upvote
  flag
The Chat for this question is dead so I'm not sure where to propose outlined changes, but I propose: 1) Change the synchronous part to a simple discussion of why it's bad with no code example of how to do it. 2) Remove/merge the callback examples to only show the more flexible Deferred approach, which I think may also be a little easier to follow for those learning Javascript. – Chris Moschini
upvote
  flag
Just one minor comment on synchronous requests.. if you're implementing something like a SCORM compliant interface, you should cache all values and return immediately for most requests, but you should do flush and exit commands synchronously to purposely block closing the channel. SCORM was a pretty horrible interface for web, and it's about the only case where you should do synchronous calls. – Tracker1
upvote
  flag
The Use deferred objects method described here was a very tidy solution which worked for me. – Andrew
upvote
  flag
@johnny: Yes. That's why the code that needs to access the response has to go inside the callback, not after the function call (as shown in the very first example of "Let functions accept callbacks"). – Felix Kling
upvote
  flag
I must commend on this most epic of answers. I have only one thing to mention. I feel the suggesting to simply not use $.getJSON seems to side step that matter. What if simple want to test the result of a successful $.getJSON and test for the existence of something inside that object? (My current situation)...//allinonescript.com/questions/33008396/… – Jessi
5 upvote
  flag
@Jessi: I think you misunderstood that part of the answer. You cannot use $.getJSON if you want the Ajax request to be synchronous. However, you should not event want the request to be synchronous, so that doesn't apply. You should be using callbacks or promises to handle the response, as it is explained earlier in the answer. – Felix Kling
upvote
  flag
I am using the jquery deferred objects of .done and .fail is that ok? I can actually see the Object inside my test via console.dir(result). I'm currently working to figure out how to test for value of something inside the object. Thank you for patience, I am a bit new at this. – Jessi
upvote
  flag
This is well explain but i still cant get mine to work and it is very Basic. The reason i dont get it its because in the foo() example there is nothing pass to the function. In my case I have foo(var1,var2,var3) so how am i suppose to call foo(function(result) { //execution... with var1,var2,var3 – MadeInDreams
upvote
  flag
using callbacks is easier if you want to unit-test your code :) – RicardoE
upvote
  flag
@RicardoE: what makes you think that? Many testing frameworks support promises. – Felix Kling
upvote
  flag
This was the one of the best explanation of how promises and asynchronous javascript works. Thank you for taking the time to share this. – Travis Michael Heller
upvote
  flag
@FelixKling I didn't said it was not supported... I said it was easier :) of course it is supported! – RicardoE
upvote
  flag
Your ajax() Promise implementation is a lot like the fetch API. – Patrick Roberts
upvote
  flag
Deprecation Notice: The jqXHR.success(), jqXHR.error(), and jqXHR.complete() callbacks are removed as of jQuery 3.0. You can use jqXHR.done(), jqXHR.fail(), and jqXHR.always() instead. – Jo Smo
upvote
  flag
Just a note of clarification - Dojo implemented "Deferred" before jQuery. So the Deferred concept is not exclusive to, nor created by jQuery – Manachi
upvote
  flag
You have used callback and myCallback , If i am correct both are same and what you mean is success: myCallback(response) ? – stom
1 upvote
  flag
@stom: "both are same" They are referring to the same value in the example. "what you mean is success: myCallback(response)" No. I really do mean success: callback. callback is the name of the parameter of foo, and the value of the parameter is assigned to success. myCallback is the name of the function is passed to foo, but that's irrelevant. Consider this simplified example: var x = 42; function foo(y) { console.log(y); }; foo(x);. y is a parameter of foo, hence console.log(y) is used. We could do console.log(x);, but that defeats the purpose of the function. – Felix Kling
upvote
  flag
Thanks for the reply, so that means when response comes from server, success will assign value to foo's callback parameter, which in turn will call foo(myCallback) and pass the value to result parameter of myCallback ? – stom
1 upvote
  flag
@stom: foo(myCallback) was already called. That's what initiates the Ajax call. But yes, when the response is received, jQuery will call the function assigned to success and pass the response to it. – Felix Kling
upvote
  flag
Can I call a js file on server from a js on client ? I mean I don't want to write php on server side. Can I call js instead of php ? – abidinberkay
upvote
  flag
@abidinberkay: AJAX uses HTTP to communicate with the server. Which HTTP server and server side language you are using is up to you. So yes. – Felix Kling
upvote
  flag
@MadaraUchiha, I strongly disagree with your recent edit (the large TL;DR: Use Promises). This question is a dup target for a large number of general async-issue questions (how to return a variable). Putting that code/info at the start is confusing to the people who we are telling this is a duplicate of their problem. The code you provided only shows how to use the Promise that is auto-returned by jQuery's $.ajax() when you don't provide a callback. You have changed a general purpose answer into one which is now only specific to $.ajax(), or functions which auto-return a Promise.(cont) – Makyen
upvote
  flag
@MadaraUchiha:(cont) This is now seen by newbies as too specific and not applicable to their question (which could be for any async function, not just $.ajax()). $.ajax() is just used as an example of the more general issue. Note that I am only here at this question/answer now because what I describe as the response newbies is what has happened when I suggested this as a dup target on a question. If you were not a moderator, I would just revert the edit while we discuss it, but I don't want to, potentially, get into a rollback contest with a moderator. – Makyen
upvote
  flag
@Makyen Feel free to revert. Thanks for your comment, I guess this needs more thinking. – Madara Uchiha
upvote
  flag
I guess with the presence of BabelJS and therefore ES7 support, this answer deserves an update for being able to actually go back to "synchronous style" using asynchronous functions by applying async / await combos. – jAndy
upvote
  flag
@jAndy: async/await is not part of ES7 (ES2016) but it will be part of ES2017. So yes, I agree that talking about it would be valuable. However, one still needs to understand promises. I see if can come up with something in the next few days (and restructure the answer a little to make it not too cluttered). – Felix Kling
upvote
  flag
since version 3.0 of jQuery Defered objects support catch() – CStff
upvote
  flag
i think this answer can do with an update since ES8 is out – DarkMukke
upvote
  flag
@DarkMukke: it already mentions async/await. What else do you think is missing? – Felix Kling
upvote
  flag
@FelixKling i'm sorry, you missunderstand, I think the post is perfect, but callback popular in node, afaik everyone is trying to move away from call backs asap in favour of promises. i just feel that statement is outdated, and I figured if 1 bit is, some other bits might too – DarkMukke

If you're not using jQuery in your code, this answer is for you

Your code should be something along the lines of this:

function foo() {
    var httpRequest = new XMLHttpRequest();
    httpRequest.open('GET', "/echo/json");
    httpRequest.send();
    return httpRequest.responseText;
}

var result = foo(); // always ends up being 'undefined'

Felix Kling did a fine job writing an answer for people using jQuery for AJAX, I've decided to provide an alternative for people who aren't.

(Note, for those using the new fetch API, Angular or promises I've added another answer below)


What you're facing

This is a short summary of "Explanation of the problem" from the other answer, if you're not sure after reading this, read that.

The A in AJAX stands for asynchronous. That means sending the request (or rather receiving the response) is taken out of the normal execution flow. In your example, .send returns immediately and the next statement, return result;, is executed before the function you passed as success callback was even called.

This means when you're returning, the listener you've defined did not execute yet, which means the value you're returning has not been defined.

Here is a simple analogy

function getFive(){ 
    var a;
    setTimeout(function(){
         a=5;
    },10);
    return a;
}

(Fiddle)

The value of a returned is undefined since the a=5 part has not executed yet. AJAX acts like this, you're returning the value before the server got the chance to tell your browser what that value is.

One possible solution to this problem is to code re-actively , telling your program what to do when the calculation completed.

function onComplete(a){ // When the code completes, do this
    alert(a);
}

function getFive(whenDone){ 
    var a;
    setTimeout(function(){
         a=5;
         whenDone(a);
    },10);
}

This is called CPS. Basically, we're passing getFive an action to perform when it completes, we're telling our code how to react when an event completes (like our AJAX call, or in this case the timeout).

Usage would be:

getFive(onComplete);

Which should alert "5" to the screen. (Fiddle).

Possible solutions

There are basically two ways how to solve this:

  1. Make the AJAX call synchronous (lets call it SJAX).
  2. Restructure your code to work properly with callbacks.

1. Synchronous AJAX - Don't do it!!

As for synchronous AJAX, don't do it! Felix's answer raises some compelling arguments about why it's a bad idea. To sum it up, it'll freeze the user's browser until the server returns the response and create a very bad user experience. Here is another short summary taken from MDN on why:

XMLHttpRequest supports both synchronous and asynchronous communications. In general, however, asynchronous requests should be preferred to synchronous requests for performance reasons.

In short, synchronous requests block the execution of code... ...this can cause serious issues...

If you have to do it, you can pass a flag: Here is how:

var request = new XMLHttpRequest();
request.open('GET', 'yourURL', false);  // `false` makes the request synchronous
request.send(null);

if (request.status === 200) {// That's HTTP for 'ok'
  console.log(request.responseText);
}

2. Restructure code

Let your function accept a callback. In the example code foo can be made to accept a callback. We'll be telling our code how to react when foo completes.

So:

var result = foo();
// code that depends on `result` goes here

Becomes:

foo(function(result) {
    // code that depends on `result`
});

Here we passed an anonymous function, but we could just as easily pass a reference to an existing function, making it look like:

function myHandler(result) {
    // code that depends on `result`
}
foo(myHandler);

For more details on how this sort of callback design is done, check Felix's answer.

Now, let's define foo itself to act accordingly

function foo(callback) {
    var httpRequest = new XMLHttpRequest();
    httpRequest.onload = function(){ // when the request is loaded
       callback(httpRequest.responseText);// we're calling our method
    };
    httpRequest.open('GET', "/echo/json");
    httpRequest.send();
}

(fiddle)

We have now made our foo function accept an action to run when the AJAX completes successfully, we can extend this further by checking if the response status is not 200 and acting accordingly (create a fail handler and such). Effectively solving our issue.

If you're still having a hard time understanding this read the AJAX getting started guide at MDN.

7 upvote
  flag
"synchronous requests block the execution of code and can leak memory and events" how can a synchronous request leak memory? – Matthew G
4 upvote
  flag
@MatthewG I've added a bounty on it in this question, I'll see what I can fish out. I'm removing the quote from the answer in the mean time. – Benjamin Gruenbaum
7 upvote
  flag
Just for the reference, XHR 2 allows us to use the onload handler, which only fires when readyState is 4. Of course, it's not supported in IE8. (iirc, may need confirmation.) – Florian Margaine
3 upvote
  flag
Your explanation of how to pass an anonymous function as a callback is valid but misleading. The example var bar = foo(); is asking for a variable to be defined, whereas your suggested foo(functim() {}); doesn't define bar – Robbie Averill
upvote
  flag
@BenjaminGruenbaum How do I return the content of result in a variable that I can use somewhere else in my code rather than printing it with html? – MorganFR

XMLHttpRequest 2 (first of all read the answers from Benjamin Gruenbaum & Felix Kling)

If you don't use jQuery and want a nice short XMLHttpRequest 2 which works on the modern browsers and also on the mobile browsers I suggest to use it this way:

function ajax(a, b, c){ // URL, callback, just a placeholder
  c = new XMLHttpRequest;
  c.open('GET', a);
  c.onload = b;
  c.send()
}

As you can see:

  1. It's shorter than all other functions Listed.
  2. The callback is set directly (so no extra unnecessary closures).
  3. It uses the new onload (so you don't have to check for readystate && status)
  4. There are some other situations which I don't remember that make the XMLHttpRequest 1 annoying.

There are two ways to get the response of this Ajax call (three using the XMLHttpRequest var name):

The simplest:

this.response

Or if for some reason you bind() the callback to a class:

e.target.response

Example:

function callback(e){
  console.log(this.response);
}
ajax('URL', callback);

Or (the above one is better anonymous functions are always a problem):

ajax('URL', function(e){console.log(this.response)});

Nothing easier.

Now some people will probably say that it's better to use onreadystatechange or the even the XMLHttpRequest variable name. That's wrong.

Check out XMLHttpRequest advanced features

It supported on all *modern browsers. And I can confirm as I'm using this approach since XMLHttpRequest 2 exists. I never had any type of problem on all browsers I use.

onreadystatechange is only useful if you want to get the headers on state 2.

Using the XMLHttpRequest variable name is another big error as you need to execute the callback inside the onload/oreadystatechange closures else you lost it.


Now if you want something more complex using post and FormData you can easily extend this function:

function x(a, b, e, d, c){ // URL, callback, method, formdata or {key:val},placeholder
  c = new XMLHttpRequest;
  c.open(e||'get', a);
  c.onload = b;
  c.send(d||null)
}

Again ... it's a very short function, but it does get & post.

Examples of usage:

x(url, callback); // By default it's get so no need to set
x(url, callback, 'post', {'key': 'val'}); // No need to set post data

Or pass a full form element (document.getElementsByTagName('form')[0]):

var fd = new FormData(form);
x(url, callback, 'post', fd);

Or set some custom values:

var fd = new FormData();
fd.append('key', 'val')
x(url, callback, 'post', fd);

As you can see I didn't implement sync... it's a bad thing.

Having said that ... why don't do it the easy way?


As mentioned in the comment the use of error && synchronous does completely break the point of the answer. Which is a nice short way to use Ajax in the proper way?

Error handler

function x(a, b, e, d, c){ // URL, callback, method, formdata or {key:val}, placeholder
  c = new XMLHttpRequest;
  c.open(e||'get', a);
  c.onload = b;
  c.onerror = error;
  c.send(d||null)
}

function error(e){
  console.log('--Error--', this.type);
  console.log('this: ', this);
  console.log('Event: ', e)
}
function displayAjax(e){
  console.log(e, this);
}
x('WRONGURL', displayAjax);

In the above script, you have an error handler which is statically defined so it does not compromise the function. The error handler can be used for other functions too.

But to really get out an error the only way is to write a wrong URL in which case every browser throws an error.

Error handlers are maybe useful if you set custom headers, set the responseType to blob array buffer or whatever....

Even if you pass 'POSTAPAPAP' as the method it won't throw an error.

Even if you pass 'fdggdgilfdghfldj' as formdata it won't throw an error.

In the first case the error is inside the displayAjax() under this.statusText as Method not Allowed.

In the second case, it simply works. You have to check at the server side if you passed the right post data.

cross-domain not allowed throws error automatically.

In the error response, there are no error codes.

There is only the this.type which is set to error.

Why add an error handler if you totally have no control over errors? Most of the errors are returned inside this in the callback function displayAjax().

So: No need for error checks if you're able to copy and paste the URL properly. ;)

PS: As the first test I wrote x('x', displayAjax)..., and it totally got a response...??? So I checked the folder where the HTML is located, and there was a file called 'x.xml'. So even if you forget the extension of your file XMLHttpRequest 2 WILL FIND IT. I LOL'd


Read a file synchronous

Don't do that.

If you want to block the browser for a while load a nice big txt file synchronous.

function omg(a, c){ // URL
  c = new XMLHttpRequest;
  c.open('GET', a, true);
  c.send();
  return c; // Or c.response
}

Now you can do

 var res = omg('thisIsGonnaBlockThePage.txt');

There is no other way to do this in a non-asynchronous way. (Yeah, with setTimeout loop... but seriously?)

Another point is... if you work with APIs or just you own list's files or whatever you always use different functions for each request...

Only if you have a page where you load always the same XML/JSON or whatever you need only one function. In that case, modify a little the Ajax function and replace b with your special function.


The functions above are for basic use.

If you want to EXTEND the function...

Yes, you can.

I'm using a lot of APIs and one of the first functions I integrate into every HTML page is the first Ajax function in this answer, with GET only...

But you can do a lot of stuff with XMLHttpRequest 2:

I made a download manager (using ranges on both sides with resume, filereader, filesystem), various image resizers converters using canvas, populate websql databases with base64images and much more... But in these cases you should create a function only for that purpose... sometimes you need a blob, array buffers, you can set headers, override mimetype and there is a lot more...

But the question here is how to return an Ajax response... (I added an easy way.)

8 upvote
  flag
While this answer is nice (And we all love XHR2 and posting file data and multipart data is totally awesome) - this shows syntactic sugar for posting XHR with JavaScript - you might want to put this in a blog post (I'd like it) or even in a library (not sure about the name x, ajax or xhr might be nicer :)). I don't see how it addresses returning the response from an AJAX call. (someone could still do var res = x("url") and not understand why it doesn't work ;)). On a side note - it would be cool if you returned c from the method so users can hook on error etc. – Benjamin Gruenbaum
15 upvote
  flag
2.ajax is meant to be async.. so NO var res=x('url').. That's the entire point of this question and answers :) – Benjamin Gruenbaum
1 upvote
  flag
why is there a 'c' parameter in the functions, if on the first line you're overwriting whatever value it had? am i missing something? – Brian H.
upvote
  flag
You can use parameters as a placeholder to avoid writing multiple times "var" – cocco
upvote
  flag
@cocco So you wrote misleading, unreadable code in a SO answer in order to save a few keystrokes? Please don't do that. – skypecakes

The simplest solution is create a JavaScript function and call it for the Ajax success callback.

function callServerAsync(){
    $.ajax({
        url: '...',
        success: function(response) {

            successCallback(response);
        }
    });
}

function successCallback(responseObj){
    // Do something like read the response and show data
    alert(JSON.stringify(responseObj)); // Only applicable to JSON response
}

function foo(callback) {

    $.ajax({
        url: '...',
        success: function(response) {
           return callback(null, response);
        }
    });
}

var result = foo(function(err, result){
          if (!err)
           console.log(result);    
}); 
1 upvote
  flag
I don't know who voted it negative. But this is a work around which has worked in fact i used this approach to create a whole application. The jquery.ajax don't return data so its better to use the above approach. If it's wrong then please explain and suggest better way to do it. – Hemant Bavle
7 upvote
  flag
Sorry, I forgot to leave a comment (I usually do!). I downvoted it. Downvotes don't indicate factual correctness or lack of, they indicate usefulness in the context or lack of. I don't find your answer useful given Felix's which already explains this only in much more detail. On a side note, why would you stringify the response if it's JSON? – Benjamin Gruenbaum
4 upvote
  flag
ok.. @Benjamin i used stringify, to convert a JSON Object to string. And thanks for clarifying your point. Will keep in mind to post more elaborate answers. – Hemant Bavle
upvote
  flag
And what if you want to return the "responseObj" outside of "successCallback" ... :) ... how will you do it ... ? ... cause a simple return will return it to the "success" callback of the ajax ... and not outside of "successCallback" ... – pesho hristov

You are using Ajax incorrectly. The idea is not to have it return anything, but instead hand off the data to something called a callback function, which handles the data.

That is:

function handleData( responseData ) {

    // Do what you want with the data
    console.log(responseData);
}

$.ajax({
    url: "hi.php",
    ...
    success: function ( data, status, XHR ) {
        handleData(data);
    }
});

Returning anything in the submit handler will not do anything. You must instead either hand off the data, or do what you want with it directly inside the success function.

6 upvote
  flag
This answer is completely semantic... your success method is just a callback within a callback. You could just have success: handleData and it would work. – Jacques
1 upvote
  flag
And what if you want to return the "responseData" outside of "handleData" ... :) ... how will you do it ... ? ... cause a simple return will return it to the "success" callback of the ajax ... and not outside of "handleData" ... – pesho hristov

Angular1

For people who are using AngularJS, can handle this situation using Promises.

Here it says,

Promises can be used to unnest asynchronous functions and allows one to chain multiple functions together.

You can find a nice explanation here also.

Example found in docs mentioned below.

  promiseB = promiseA.then(
    function onSuccess(result) {
      return result + 1;
    }
    ,function onError(err) {
      //Handle error
    }
  );

 // promiseB will be resolved immediately after promiseA is resolved 
 // and its value will be the result of promiseA incremented by 1.

Angular2 and Later

In Angular2 with look at the following example, but its recommended to use Observables with Angular2.

 search(term: string) {
     return this.http
  .get(`https://api.spotify.com/v1/search?q=${term}&type=artist`)
  .map((response) => response.json())
  .toPromise();

}

You can consume that in this way,

search() {
    this.searchService.search(this.searchField.value)
      .then((result) => {
    this.result = result.artists.items;
  })
  .catch((error) => console.error(error));
}

See the original post here. But Typescript does not support native es6 Promises, if you want to use it, you might need plugin for that.

Additionally here is the promises spec define here.

9 upvote
  flag
This does not explain how promises would solve this issue at all though. – Benjamin Gruenbaum
3 upvote
  flag
It doesn't work. promiseB will get 'undefined' – An Overflowed Stack
2 upvote
  flag
jQuery and fetch methods both return promises as well. I would suggest revising your answer. Though jQuery's isn't quite the same (then is there, but catch isn't). – Tracker1
1 upvote
  flag
jQuery also has promises – Vatsal
1 upvote
  flag
@Tracker1 I've added a proper promises answer now, figured this is about time. – Benjamin Gruenbaum

Another approach to return a value from an asynchronous function, is to pass in an object that will store the result from the asynchronous function.

Here is an example of the same:

var async = require("async");

// This wires up result back to the caller
var result = {};
var asyncTasks = [];
asyncTasks.push(function(_callback){
    // some asynchronous operation
    $.ajax({
        url: '...',
        success: function(response) {
            result.response = response;
            _callback();
        }
    });
});

async.parallel(asyncTasks, function(){
    // result is available after performing asynchronous operation
    console.log(result)
    console.log('Done');
});

I am using the result object to store the value during the asynchronous operation. This allows the result be available even after the asynchronous job.

I use this approach a lot. I would be interested to know how well this approach works where wiring the result back through consecutive modules is involved.

6 upvote
  flag
There is nothing special about using an object here. It would work as well if you assigned he response directly to result. It works because you are reading the variable after the async function is complete. – Felix Kling

Short answer: Your foo() method returns immediately, while the $ajax() call executes asynchronously after the function returns. The problem is then how or where to store the results retrieved by the async call once it returns.

Several solutions have been given in this thread. Perhaps the easiest way is to pass an object to the foo() method, and to store the results in a member of that object after the async call completes.

function foo(result) {
    $.ajax({
        url: '...',
        success: function(response) {
            result.response = response;   // Store the async result
        }
    });
}

var result = { response: null };   // Object to hold the async result
foo(result);                       // Returns before the async completes

Note that the call to foo() will still return nothing useful. However, the result of the async call will now be stored in result.response.

10 upvote
  flag
While this works, it's not really better than assigning to a global variable. – Felix Kling

While promises and callbacks work fine in many situations, it is a pain in the rear to express something like:

if (!name) {
  name = async1();
}
async2(name);

You'd end up going through async1; check if name is undefined or not and call the callback accordingly.

async1(name, callback) {
  if (name)
    callback(name)
  else {
    doSomething(callback)
  }
}

async1(name, async2)

While it is okay in small examples it gets annoying when you have a lot of similar cases and error handling involved.

Fibers helps in solving the issue.

var Fiber = require('fibers')

function async1(container) {
  var current = Fiber.current
  var result
  doSomething(function(name) {
    result = name
    fiber.run()
  })
  Fiber.yield()
  return result
}

Fiber(function() {
  var name
  if (!name) {
    name = async1()
  }
  async2(name)
  // Make any number of async calls from here
}

You can checkout the project here.

upvote
  flag
does not download... – recurf
upvote
  flag
@recurf - It's not my project. You could try using their issue tracker. – rohithpr
upvote
  flag
is this similar to generator functions? developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…* – Emanegux

The following example I have written shows how to

  • Handle asynchronous HTTP calls;
  • Wait for response from each API call;
  • Use Promise pattern;
  • Use Promise.All pattern to join multiple HTTP calls;

This working example is self-contained. It will define a simple request object that uses the window XMLHttpRequest object to make calls. It will define a simple function to wait for a bunch of promises to be completed.

Context. The example is querying the Spotify Web API endpoint in order to search for playlist objects for a given set of query strings:

[
 "search?type=playlist&q=%22doom%20metal%22",
 "search?type=playlist&q=Adele"
]

For each item, a new Promise will fire a block - ExecutionBlock, parse the result, schedule a new set of promises based on the result array, that is a list of Spotify user objects and execute the new HTTP call within the ExecutionProfileBlock asynchronously.

You can then see a nested Promise structure, that lets you spawn multiple and completely asynchronous nested HTTP calls, and join the results from each subset of calls through Promise.all.

NOTE Recent Spotify search APIs will require an access token to be specified in the request headers:

-H "Authorization: Bearer {your access token}" 

So, you to run the following example you need to put your access token in the request headers:

var spotifyAccessToken = "YourSpotifyAccessToken";
var console = {
    log: function(s) {
        document.getElementById("console").innerHTML += s + "<br/>"
    }
}

// Simple XMLHttpRequest
// based on https://davidwalsh.name/xmlhttprequest
SimpleRequest = {
    call: function(what, response) {
        var request;
        if (window.XMLHttpRequest) { // Mozilla, Safari, ...
            request = new XMLHttpRequest();
        } else if (window.ActiveXObject) { // Internet Explorer
            try {
                request = new ActiveXObject('Msxml2.XMLHTTP');
            }
            catch (e) {
                try {
                  request = new ActiveXObject('Microsoft.XMLHTTP');
                } catch (e) {}
            }
        }

        // State changes
        request.onreadystatechange = function() {
            if (request.readyState === 4) { // Done
                if (request.status === 200) { // Complete
                    response(request.responseText)
                }
                else
                    response();
            }
        }
        request.open('GET', what, true);
        request.setRequestHeader("Authorization", "Bearer " + spotifyAccessToken);
        request.send(null);
    }
}

//PromiseAll
var promiseAll = function(items, block, done, fail) {
    var self = this;
    var promises = [],
                   index = 0;
    items.forEach(function(item) {
        promises.push(function(item, i) {
            return new Promise(function(resolve, reject) {
                if (block) {
                    block.apply(this, [item, index, resolve, reject]);
                }
            });
        }(item, ++index))
    });
    Promise.all(promises).then(function AcceptHandler(results) {
        if (done) done(results);
    }, function ErrorHandler(error) {
        if (fail) fail(error);
    });
}; //promiseAll

// LP: deferred execution block
var ExecutionBlock = function(item, index, resolve, reject) {
    var url = "https://api.spotify.com/v1/"
    url += item;
    console.log( url )
    SimpleRequest.call(url, function(result) {
        if (result) {

            var profileUrls = JSON.parse(result).playlists.items.map(function(item, index) {
                return item.owner.href;
            })
            resolve(profileUrls);
        }
        else {
            reject(new Error("call error"));
        }
    })
}

arr = [
    "search?type=playlist&q=%22doom%20metal%22",
    "search?type=playlist&q=Adele"
]

promiseAll(arr, function(item, index, resolve, reject) {
    console.log("Making request [" + index + "]")
    ExecutionBlock(item, index, resolve, reject);
}, function(results) { // Aggregated results

    console.log("All profiles received " + results.length);
    //console.log(JSON.stringify(results[0], null, 2));

    ///// promiseall again

    var ExecutionProfileBlock = function(item, index, resolve, reject) {
        SimpleRequest.call(item, function(result) {
            if (result) {
                var obj = JSON.parse(result);
                resolve({
                    name: obj.display_name,
                    followers: obj.followers.total,
                    url: obj.href
                });
            } //result
        })
    } //ExecutionProfileBlock

    promiseAll(results[0], function(item, index, resolve, reject) {
        //console.log("Making request [" + index + "] " + item)
        ExecutionProfileBlock(item, index, resolve, reject);
    }, function(results) { // aggregated results
        console.log("All response received " + results.length);
        console.log(JSON.stringify(results, null, 2));
    }

    , function(error) { // Error
        console.log(error);
    })

    /////

  },
  function(error) { // Error
      console.log(error);
  });
<div id="console" />

I have extensively discussed this solution here.

Short answer is, you have to implement a callback like this:

function callback(response) {
    // Here you can do what ever you want with the response object.
    console.log(response);
}

$.ajax({
    url: "...",
    success: callback
});

You can use this custom library (written using Promise) to make a remote call.

function $http(apiConfig) {
    return new Promise(function (resolve, reject) {
        var client = new XMLHttpRequest();
        client.open(apiConfig.method, apiConfig.url);
        client.send();
        client.onload = function () {
            if (this.status >= 200 && this.status < 300) {
                // Performs the function "resolve" when this.status is equal to 2xx.
                // Your logic here.
                resolve(this.response);
            }
            else {
                // Performs the function "reject" when this.status is different than 2xx.
                reject(this.statusText);
            }
        };
        client.onerror = function () {
            reject(this.statusText);
        };
    });
}

Simple usage example:

$http({
    method: 'get',
    url: 'google.com'
}).then(function(response) {
    console.log(response);
}, function(error) {
    console.log(error)
});

Have a look at this example:

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope,$http) {

    var getJoke = function(){
        return $http.get('http://api.icndb.com/jokes/random').then(function(res){
            return res.data.value;  
        });
    }

    getJoke().then(function(res) {
        console.log(res.joke);
    });
});

As you can see getJoke is returning a resolved promise (it is resolved when returning res.data.value). So you wait until the $http.get request is completed and then console.log(res.joke) is executed (as a normal asynchronous flow).

This is the plnkr:

http://embed.plnkr.co/XlNR7HpCaIhJxskMJfSg/

I will answer with a horrible-looking, hand-drawn comic. The second image is the reason why result is undefined in your code example.

enter image description here

8 upvote
  flag
A picture is worth a thousand words, Person A - Ask's person B details to fix his car, in turn Person B - Makes Ajax Call and waits for response from server for car fixing details, when response is received, Ajax Success function calls the Person B function and passes the response as argument to it, Person A receives the answer. – stom

Here are some approaches to work with asynchronous requests:

  1. Browser Promise object
  2. Q - A promise library for JavaScript
  3. A+ Promises.js
  4. jQuery deferred
  5. XMLHttpRequest API
  6. Using callback concept - As implementation in first answer

Example: jQuery deferred implementation to work with multiple requests

var App = App || {};

App = {
    getDataFromServer: function(){

      var self = this,
                 deferred = $.Deferred(),
                 requests = [];

      requests.push($.getJSON('request/ajax/url/1'));
      requests.push($.getJSON('request/ajax/url/2'));

      $.when.apply(jQuery, requests).done(function(xhrResponse) {
        return deferred.resolve(xhrResponse.result);
      });
      return deferred;
    },

    init: function(){

        this.getDataFromServer().done(_.bind(function(resp1, resp2) {

           // Do the operations which you wanted to do when you
           // get a response from Ajax, for example, log response.
        }, this));
    }
};
App.init();

Use a callback() function inside the foo() success. Try in this way. It is simple and easy to understand.

var lat = "";
var lon = "";
function callback(data){
    lat = data.lat;
    lon = data.lon;
}
function getLoc() {
  var url = "http://ip-api.com/json"
  $.getJSON(url, function(data) {
    callback(data);
  });
}

getLoc();

Most of the answers here give useful suggestions for when you have a single async operation, but sometimes, this comes up when you need to do an asynchronous operation for each entry in an array or other list-like structure. The temptation is to do this:

// WRONG
var results = [];
theArray.forEach(function(entry) {
    doSomethingAsync(entry, function(result) {
        results.push(result);
    });
});
console.log(results); // E.g., using them, returning them, etc.

Example:

// WRONG
var theArray = [1, 2, 3];
var results = [];
theArray.forEach(function(entry) {
    doSomethingAsync(entry, function(result) {
        results.push(result);
    });
});
console.log("Results:", results); // E.g., using them, returning them, etc.

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

The reason that doesn't work is that the callbacks from doSomethingAsync haven't run yet by the time you're trying to use the results.

So, if you have an array (or list of some kind) and want to do async operations for each entry, you have two options: Do the operations in parallel (overlapping), or in series (one after another in sequence).

Parallel

You can start all of them and keep track of how many callbacks you're expecting, and then use the results when you've gotten that many callbacks:

var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
    doSomethingAsync(entry, function(result) {
        results[index] = result;
        if (--expecting === 0) {
            // Done!
            console.log("Results:", results); // E.g., using the results
        }
    });
});

Example:

var theArray = [1, 2, 3];
var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
    doSomethingAsync(entry, function(result) {
        results[index] = result;
        if (--expecting === 0) {
            // Done!
            console.log("Results:", results); // E.g., using the results
        }
    });
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

(We could do away with expecting and just use results.length === theArray.length, but that leaves us open to the possibility that theArray is changed while the calls are outstanding...)

Notice how we use the index from forEach to save the result in results in the same position as the entry it relates to, even if the results arrive out of order (since async calls don't necessarily complete in the order in which they were started).

But what if you need to return those results from a function? As the other answers have pointed out, you can't; you have to have your function accept and call a callback (or return a Promise). Here's a callback version:

function doSomethingWith(theArray, callback) {
    var results = [];
    var expecting = theArray.length;
    theArray.forEach(function(entry, index) {
        doSomethingAsync(entry, function(result) {
            results[index] = result;
            if (--expecting === 0) {
                // Done!
                callback(results);
            }
        });
    });
}
doSomethingWith(theArray, function(results) {
    console.log("Results:", results);
});

Example:

function doSomethingWith(theArray, callback) {
    var results = [];
    var expecting = theArray.length;
    theArray.forEach(function(entry, index) {
        doSomethingAsync(entry, function(result) {
            results[index] = result;
            if (--expecting === 0) {
                // Done!
                callback(results);
            }
        });
    });
}
doSomethingWith([1, 2, 3], function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

Or here's a version returning a Promise instead:

function doSomethingWith(theArray) {
    return new Promise(function(resolve) {
        var results = [];
        var expecting = theArray.length;
        theArray.forEach(function(entry, index) {
            doSomethingAsync(entry, function(result) {
                results[index] = result;
                if (--expecting === 0) {
                    // Done!
                    resolve(results);
                }
            });
        });
    });
}
doSomethingWith(theArray).then(function(results) {
    console.log("Results:", results);
});

Of course, if doSomethingAsync passed us errors, we'd use reject to reject the promise when we got an error.)

Example:

function doSomethingWith(theArray) {
    return new Promise(function(resolve) {
        var results = [];
        var expecting = theArray.length;
        theArray.forEach(function(entry, index) {
            doSomethingAsync(entry, function(result) {
                results[index] = result;
                if (--expecting === 0) {
                    // Done!
                    resolve(results);
                }
            });
        });
    });
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

(Or alternately, you could make a wrapper for doSomethingAsync that returns a promise, and then do the below...)

If doSomethingAsync gives you a Promise, you can use Promise.all:

function doSomethingWith(theArray) {
    return Promise.all(theArray.map(function(entry) {
        return doSomethingAsync(entry, function(result) {
            results.push(result);
        });
    }));
}
doSomethingWith(theArray).then(function(results) {
    console.log("Results:", results);
});

Example:

function doSomethingWith(theArray) {
    return Promise.all(theArray.map(function(entry) {
        return doSomethingAsync(entry, function(result) {
            results.push(result);
        });
    }));
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value) {
    console.log("Starting async operation for " + value);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log("Completing async operation for " + value);
            resolve(value * 2);
        }, Math.floor(Math.random() * 200));
    });
}
.as-console-wrapper {
  max-height: 100% !important;
}

Note that Promise.all resolves its promise with an array of the results of all of the promises you give it when they are all resolved, or rejects its promise when the first of the promises you give it rejects.

Series

Suppose you don't want the operations to be in parallel? If you want to run them one after another, you need to wait for each operation to complete before you start the next. Here's an example of a function that does that and calls a callback with the result:

function doSomethingWith(theArray, callback) {
    var results = [];
    doOne(0);
    function doOne(index) {
        if (index < theArray.length) {
            doSomethingAsync(theArray[index], function(result) {
                results.push(result);
                doOne(index + 1);
            });
        } else {
            // Done!
            callback(results);
        }
    }
}
doSomethingWith(theArray, function(results) {
    console.log("Results:", results);
});

(Since we're doing the work in series, we can just use results.push(result) since we know we won't get results out of order. In the above we could have used results[index] = result;, but in some of the following examples we don't have an index to use.)

Example:

function doSomethingWith(theArray, callback) {
    var results = [];
    doOne(0);
    function doOne(index) {
        if (index < theArray.length) {
            doSomethingAsync(theArray[index], function(result) {
                results.push(result);
                doOne(index + 1);
            });
        } else {
            // Done!
            callback(results);
        }
    }
}
doSomethingWith([1, 2, 3], function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value, callback) {
    console.log("Starting async operation for " + value);
    setTimeout(function() {
        console.log("Completing async operation for " + value);
        callback(value * 2);
    }, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
  max-height: 100% !important;
}

(Or, again, build a wrapper for doSomethingAsync that gives you a promise and do the below...)

If doSomethingAsync gives you a Promise, if you can use ES2017+ syntax (perhaps with a transpiler like Babel), you can use an async function with for-of and await:

async function doSomethingWith(theArray) {
    const results = [];
    for (const entry of theArray) {
        results.push(await doSomethingAsync(entry));
    }
    return results;
}
doSomethingWith(theArray).then(results => {
    console.log("Results:", results);
});

Example:

async function doSomethingWith(theArray) {
    const results = [];
    for (const entry of theArray) {
        results.push(await doSomethingAsync(entry));
    }
    return results;
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value) {
    console.log("Starting async operation for " + value);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log("Completing async operation for " + value);
            resolve(value * 2);
        }, Math.floor(Math.random() * 200));
    });
}
.as-console-wrapper {
  max-height: 100% !important;
}

If you can't use ES2017+ syntax (yet), you can use a variation on the "Promise reduce" pattern (this is more complex than the usual Promise reduce because we're not passing the result from one into the next, but instead gathering up their results in an array):

function doSomethingWith(theArray) {
    return theArray.reduce(function(p, entry) {
        return p.then(function(results) {
            return doSomethingAsync(entry).then(function(result) {
                results.push(result);
                return results;
            });
        });
    }, Promise.resolve([]));
}
doSomethingWith(theArray).then(function(results) {
    console.log("Results:", results);
});

Example:

function doSomethingWith(theArray) {
    return theArray.reduce(function(p, entry) {
        return p.then(function(results) {
            return doSomethingAsync(entry).then(function(result) {
                results.push(result);
                return results;
            });
        });
    }, Promise.resolve([]));
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value) {
    console.log("Starting async operation for " + value);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log("Completing async operation for " + value);
            resolve(value * 2);
        }, Math.floor(Math.random() * 200));
    });
}
.as-console-wrapper {
  max-height: 100% !important;
}

...which is less cumbersome with ES2015+ arrow functions:

function doSomethingWith(theArray) {
    return theArray.reduce((p, entry) => p.then(results => doSomethingAsync(entry).then(result => {
        results.push(result);
        return results;
    })), Promise.resolve([]));
}
doSomethingWith(theArray).then(results => {
    console.log("Results:", results);
});

Example:

function doSomethingWith(theArray) {
    return theArray.reduce((p, entry) => p.then(results => doSomethingAsync(entry).then(result => {
        results.push(result);
        return results;
    })), Promise.resolve([]));
}
doSomethingWith([1, 2, 3]).then(function(results) {
    console.log("Results:", results);
});

function doSomethingAsync(value) {
    console.log("Starting async operation for " + value);
    return new Promise(function(resolve) {
        setTimeout(function() {
            console.log("Completing async operation for " + value);
            resolve(value * 2);
        }, Math.floor(Math.random() * 200));
    });
}
.as-console-wrapper {
  max-height: 100% !important;
}

upvote
  flag
Could you explain how the if (--expecting === 0) part of the code works please? The callback version of your solution is working great for me, I just don't understand how, with that statement, you are checking the number of responses completed. Appreciate it's just lack of knowledge on my part. Is there an alternative way that check could be written? – Sarah
upvote
  flag
@Sarah: expecting starts out with the value of array.length, which is how many requests we're going to make. We know the callback won't be called until all of those requests are started. In the callback, if (--expecting === 0) does this: 1. Decrements expecting (we've received a response, so we're expecting one fewer response) and if the value after the decrement is 0 (we're not expecting any more responses), we're done! – T.J. Crowder

This is one of the places which two ways data binding that's used in many new JavaScript frameworks will work greatly!

So if you are using Angular, React or any other frameworks which do two ways data binding, this issue is simply fixed, so in easy word, your result is undefined at the first stage, so you have got result = undefined before you recieve the data, then as soon as you get the result, it will updated and get assigned to the new value which is respond 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() or then() 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:

$(document).ready(function(){
    function foo() {
        $.ajax({url: "api/data", success: function(data){
            fooDone(data); //after we have data, we pass it to fooDone
        }});
    };

    function fooDone(data) {
        console.log(data); //fooDone has the data and console.log it
    };

    foo(); //call happens here
});

For more information study about promises and observables which are newer ways to do this async stuffs.

upvote
  flag
This is fine at global scope, but in some module context you probably want to ensure right context for the callback e.g. $.ajax({url: "api/data", success: fooDone.bind(this)}); – steve.sims

Another solution is to execute code via sequential executor nsynjs.

If underlying function is promisified

nsynjs will evaluate all promises sequentially, and put promise result into data property:

function synchronousCode() {

    var getURL = function(url) {
        return window.fetch(url).data.text().data;
    };
    
    var url = 'https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js';
    console.log('received bytes:',getURL(url).length);
    
};

nsynjs.run(synchronousCode,{},function(){
    console.log('synchronousCode done');
});
<script src="https://rawgit.com/amaksr/nsynjs/master/nsynjs.js"></script>

If underlying function is not promisified

Step 1. Wrap function with callback into nsynjs-aware wrapper (if it has promisified version, you can skip this test):

var ajaxGet = function (ctx,url) {
    var res = {};
    var ex;
    $.ajax(url)
    .done(function (data) {
        res.data = data;
    })
    .fail(function(e) {
        ex = e;
    })
    .always(function() {
        ctx.resume(ex);
    });
    return res;
};
ajaxGet.nsynjsHasCallback = true;

Step 2. Put synchronous logic into function:

function process() {
    console.log('got data:', ajaxGet(nsynjsCtx, "data/file1.json").data);
}

Step 3. Run function in synchronous manner via nnsynjs:

nsynjs.run(process,this,function () {
    console.log("synchronous function finished");
});

Nsynjs will evaluate all operators and expressions step-by-step, pausing execution in case if result of some slow function is not ready.

More examples here: https://github.com/amaksr/nsynjs/tree/master/examples

upvote
  flag
This is interesting. I like how it allows to code async calls the way you'd do it in other languages. But technically it's not real JavaScript? – J Morris

2017 answer: you can now do exactly what you want in every current browser and node 7+

This is quite simple:

  • Use the 'await', which will tell JavaScript to await a thing that returns a promise to be resolved
  • Add the 'async' keyword to the parent function

Here's a working version of your code:

(async function(){

var response = await superagent.get('...')
console.log(response)

})()

await is supported in all current browsers and node 8

1 upvote
  flag
Unfortunately, this works only with functions that return promises – for example it doesn't work with Node.js API, which uses callbacks. And I wouldn't recommend using it without Babel, because not everyone uses "current browsers". – Michał Perłakowski
1 upvote
  flag
@MichałPerłakowski node 8 includes nodejs.org/api/util.html#util_util_promisify_original which can be used to make the node.js API return promises. Whether you have the time and money to support non-current browsers obviously depends on your situation. – mikemaccana

Of course there are many approaches like synchronous request, promise, but from my experience I think you should use the callback approach. It's natural to asynchronous behavior of Javascript. So, your code snippet can be rewrite a little different:

function foo() {
    var result;

    $.ajax({
        url: '...',
        success: function(response) {
            myCallback(response);
        }
    });

    return result;
}

function myCallback(response) {
    // Does something.
}

To handle any ajax, promise, setTimeout check promise in JavaScript. $.Deferred in jQuery. Here is how you can handle the response return.

function foo() {

  var result = $.ajax({
    url: '...',
    // This success callback is not required. You can remove it. 
    // Since we are getting at (1)
    success: function (response) {
      // result = response;
    }
  });

  return result;
}

// Since this is a Promise object called $Deferred in jQuery
// You can attach a then callback which accepts two callback
// first one success and second one error


foo().then(
  function( response ) {
    // This is success callback (1)
    console.log('success: ', response);
  }, function( xhr ) {
    // This is error callback
    console.log('error: ', xhr);
  }
)

We can use JSON.stringify(obj); to convert the object into JSON and then return it to the calling function

upvote
  flag
"We can use JSON.stringify(obj); to convert the object into JSON" — You can, but it is pointless to do so. – Quentin
upvote
  flag
"then return it to the calling function" — No, you can't. – Quentin

Not the answer you're looking for? Browse other questions tagged or ask your own question.