Note: This answer was written in February 2010.
See updates from 2015, 2016 and 2017 at the bottom.
You can't return anything from a function that is asynchronous. What you can return is a promise. I explained how promises work in jQuery in my answers to those questions:
- JavaScript function that returns AJAX call data
- jQuery jqXHR - cancel chained calls, trigger error chain
If you could explain why do you want to return the data and what do you want to do with it later, then I might be able to give you a more specific answer how to do it.
Generally, instead of:
function testAjax() {
$.ajax({
url: "getvalue.php",
success: function(data) {
return data;
}
});
}
you can write your testAjax function like this:
function testAjax() {
return $.ajax({
url: "getvalue.php"
});
}
Then you can get your promise like this:
var promise = testAjax();
You can store your promise, you can pass it around, you can use it as an argument in function calls and you can return it from functions, but when you finally want to use your data that is returned by the AJAX call, you have to do it like this:
promise.success(function (data) {
alert(data);
});
(See updates below for simplified syntax.)
If your data is available at this point then this function will be invoked immediately. If it isn't then it will be invoked as soon as the data is available.
The whole point of doing all of this is that your data is not available immediately after the call to $.ajax because it is asynchronous. Promises is a nice abstraction for functions to say: I can't return you the data because I don't have it yet and I don't want to block and make you wait so here's a promise instead and you'll be able to use it later, or to just give it to someone else and be done with it.
See this DEMO.
UPDATE (2015)
Currently (as of March, 2015) jQuery Promises are not compatible with the Promises/A+ specification which means that they may not cooperate very well with other Promises/A+ conformant implementations.
However jQuery Promises in the upcoming version 3.x will be compatible with the Promises/A+ specification (thanks to Benjamin Gruenbaum for pointing it out). Currently (as of May, 2015) the stable versions of jQuery are 1.x and 2.x.
What I explained above (in March, 2011) is a way to use jQuery Deferred Objects to do something asynchronously that in synchronous code would be achieved by returning a value.
But a synchronous function call can do two things - it can either return a value (if it can) or throw an exception (if it can't return a value). Promises/A+ addresses both of those use cases in a way that is pretty much as powerful as exception handling in synchronous code. The jQuery version handles the equivalent of returning a value just fine but the equivalent of complex exception handling is somewhat problematic.
In particular, the whole point of exception handling in synchronous code is not just giving up with a nice message, but trying to fix the problem and continue the execution, or possibly rethrowing the same or a different exception for some other parts of the program to handle. In synchronous code you have a call stack. In asynchronous call you don't and advanced exception handling inside of your promises as required by the Promises/A+ specification can really help you write code that will handle errors and exceptions in a meaningful way even for complex use cases.
For differences between jQuery and other implementations, and how to convert jQuery promises to Promises/A+ compliant, see Coming from jQuery by Kris Kowal et al. on the Q library wiki and Promises arrive in JavaScript by Jake Archibald on HTML5 Rocks.
How to return a real promise
The function from my example above:
function testAjax() {
return $.ajax({
url: "getvalue.php"
});
}
returns a jqXHR object, which is a jQuery Deferred Object.
To make it return a real promise, you can change it to - using the method from the Q wiki:
function testAjax() {
return Q($.ajax({
url: "getvalue.php"
}));
}
or, using the method from the HTML5 Rocks article:
function testAjax() {
return Promise.resolve($.ajax({
url: "getvalue.php"
}));
}
This Promise.resolve($.ajax(...))
is also what is explained in the promise module documentation and it should work with ES6 Promise.resolve().
To use the ES6 Promises today you can use es6-promise module's polyfill() by Jake Archibald.
To see where you can use the ES6 Promises without the polyfill, see: Can I use: Promises.
For more info see:
- http://bugs.jquery.com/ticket/14510
- https://github.com/jquery/jquery/issues/1722
- https://gist.github.com/domenic/3889970
- http://promises-aplus.github.io/promises-spec/
- http://www.html5rocks.com/en/tutorials/es6/promises/
Future of jQuery
Future versions of jQuery (starting from 3.x - current stable versions as of May 2015 are 1.x and 2.x) will be compatible with the Promises/A+ specification (thanks to Benjamin Gruenbaum for pointing it out in the comments). "Two changes that we've already decided upon are Promise/A+ compatibility for our Deferred implementation [...]" (jQuery 3.0 and the future of Web development). For more info see: jQuery 3.0: The Next Generations by Dave Methvin and jQuery 3.0: More interoperability, less Internet Explorer by Paul Krill.
Interesting talks
- Boom, Promises/A+ Was Born by Domenic Denicola (JSConfUS 2013)
- Redemption from Callback Hell by Michael Jackson and Domenic Denicola (HTML5DevConf 2013)
- JavaScript Promises by David M. Lee (Nodevember 2014)
UPDATE (2016)
There is a new syntax in ECMA-262, 6th Edition, Section 14.2 called arrow functions that may be used to further simplify the examples above.
Using the jQuery API, instead of:
promise.success(function (data) {
alert(data);
});
you can write:
promise.success(data => alert(data));
or using the Promises/A+ API:
promise.then(data => alert(data));
Remember to always use rejection handlers either with:
promise.then(data => alert(data), error => alert(error));
or with:
promise.then(data => alert(data)).catch(error => alert(error));
See this answer to see why you should always use rejection handlers with promises:
- Should I refrain from handling Promise rejection asynchronously?
Of course in this example you could use just promise.then(alert)
because you're just calling alert
with the same arguments as your callback, but the arrow syntax is more general and lets you write things like:
promise.then(data => alert("x is " + data.x));
Not every browser supports this syntax yet, but there are certain cases when you're sure what browser your code will run on - e.g. when writing a Chrome extension, a Firefox Add-on, or a desktop application using Electron, NW.js or AppJS (see this answer for details).
For the support of arrow functions, see:
- http://caniuse.com/#feat=arrow-functions
- http://kangax.github.io/compat-table/es6/#test-arrow_functions
UPDATE (2017)
There is an even newer syntax right now called async functions with a new await
keyword that instead of this code:
functionReturningPromise()
.then(data => console.log('Data:', data))
.catch(error => console.log('Error:', error));
lets you write:
try {
let data = await functionReturningPromise();
console.log('Data:', data);
} catch (error) {
console.log('Error:', error);
}
You can only use it inside of a function created with the async
keyword. For more info, see:
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await
For support in browsers, see:
- http://caniuse.com/async-functions
For support in Node, see:
- http://node.green/#ES2017-features-async-functions
In places where you don't have native support for async
and await
you can use Babel:
- https://babeljs.io/docs/plugins/transform-async-to-generator/
or with a slightly different syntax a generator based approach like in co
or Bluebird coroutines:
- https://www.npmjs.com/package/co
- http://bluebirdjs.com/docs/api/promise.coroutine.html
More info
Some other questions about promises for more details:
- promise call separate from promise-resolution
- Q Promise delay
- Return Promise result instead of Promise
- Exporting module from promise result
- What is wrong with promise resolving?
- Return value in function from a promise block
- How can i return status inside the promise?
- Should I refrain from handling Promise rejection asynchronously?
- Is the deferred/promise concept in JavaScript a new one or is it a traditional part of functional programming?
- How can I chain these functions together with promises?
- Promise.all in JavaScript: How to get resolve value for all promises?
- Why Promise.all is undefined
- function will return null from javascript post/get
- Use cancel() inside a then-chain created by promisifyAll
- Why is it possible to pass in a non-function parameter to Promise.then() without causing an error?
- Implement promises pattern
- Promises and performance
- Trouble scraping two URLs with promises
- http.request not returning data even after specifying return on the 'end' event
- async.each not iterating when using promises
- jQuery jqXHR - cancel chained calls, trigger error chain
- Correct way of handling promisses and server response
- Return a value from a function call before completing all operations within the function itself?
- Resolving a setTimeout inside API endpoint
- Async wait for a function
- JavaScript function that returns AJAX call data
- try/catch blocks with async/await
- jQuery Deferred not calling the resolve/done callbacks in order
- Returning data from ajax results in strange object
- javascript - Why is there a spec for sync and async modules?