注:本文撰写于2010年2月。下面是2015年、2016年和2017年的更新。
你不能从异步函数返回任何东西。你能回报的是一个承诺。我在回答这些问题时解释了承诺是如何在jQuery中工作的:
返回AJAX调用数据的JavaScript函数
取消链式调用,触发错误链
如果你能解释一下你为什么要返回数据,以及你以后想用它做什么,那么我也许能给你一个更具体的答案如何做。
一般来说,不要:
function testAjax() {
$.ajax({
url: "getvalue.php",
success: function(data) {
return data;
}
});
}
你可以这样写你的testAjax函数:
function testAjax() {
return $.ajax({
url: "getvalue.php"
});
}
然后你可以得到这样的承诺:
var promise = testAjax();
你可以存储你的承诺,你可以传递它,你可以在函数调用中使用它作为参数,你可以从函数中返回它,但是当你最终想要使用AJAX调用返回的数据时,你必须这样做:
promise.success(function (data) {
alert(data);
});
(请参阅下面的更新以了解简化的语法。)
如果此时数据可用,则将立即调用此函数。如果不是,那么一旦数据可用,就会立即调用它。
执行所有这些操作的目的是,在调用$之后,您的数据不会立即可用。Ajax,因为它是异步的。承诺是对函数的一个很好的抽象,它说:我不能返回数据给你,因为我还没有它,我不想阻塞,让你等待,所以这里有一个承诺,你以后可以使用它,或者把它给别人,然后完成它。
请看这个演示。
更新(2015)
目前(截至2015年3月),jQuery承诺与承诺/A+规范不兼容,这意味着它们可能不能很好地与其他承诺/A+兼容的实现合作。
但是jQuery在即将到来的版本3中承诺。x将与Promises/A+规范兼容(感谢Benjamin Gruenbaum指出这一点)。目前(截至2015年5月)jQuery的稳定版本是1。X和2.x。
我在上面(2011年3月)解释的是一种使用jQuery延迟对象来异步做一些事情的方法,在同步代码中可以通过返回一个值来实现。
但是同步函数调用可以做两件事——它可以返回一个值(如果可以)或者抛出一个异常(如果不能返回值)。Promises/A+以一种与同步代码中的异常处理一样强大的方式处理了这两个用例。jQuery版本可以处理返回值的等价操作,但是复杂异常处理的等价操作有些问题。
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.
关于jQuery和其他实现之间的区别,以及如何将jQuery承诺转换为承诺/A+兼容,请参阅Kris Kowal等人在Q库wiki上的来自jQuery和Jake Archibald在HTML5 Rocks上的承诺到达JavaScript。
如何回报一个真正的承诺
上面例子中的函数:
function testAjax() {
return $.ajax({
url: "getvalue.php"
});
}
返回一个jqXHR对象,这是一个jQuery延迟对象。
为了让它返回一个真正的承诺,你可以把它改成-使用Q wiki的方法:
function testAjax() {
return Q($.ajax({
url: "getvalue.php"
}));
}
或者,使用HTML5 Rocks文章中的方法:
function testAjax() {
return Promise.resolve($.ajax({
url: "getvalue.php"
}));
}
这个promise .resolve($.ajax(…))也是在promise模块文档中解释的,它应该与ES6 promise .resolve()一起工作。
今天要使用ES6 Promises,你可以使用Jake Archibald编写的ES6 -promise模块的polyfill()。
要查看在哪里可以使用没有填充的ES6承诺,请参阅:我可以使用:承诺。
更多信息见:
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/
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.
有趣的对话
《Boom, Promises/A+》作者:Domenic Denicola (JSConfUS 2013)
Michael Jackson和Domenic Denicola的救赎(HTML5DevConf 2013)
JavaScript承诺作者:David M. Lee(2014年11月)
更新(2016)
在ECMA-262,第6版,章节14.2中有一个新的语法叫做箭头函数,可以用来进一步简化上面的例子。
使用jQuery API,而不是:
promise.success(function (data) {
alert(data);
});
你可以这样写:
promise.success(data => alert(data));
或使用Promises/A+ API:
promise.then(data => alert(data));
记住总是使用拒绝处理程序:
promise.then(data => alert(data), error => alert(error));
或:
promise.then(data => alert(data)).catch(error => alert(error));
看看这个答案,看看为什么你应该总是使用拒绝处理程序承诺:
我应该避免异步处理Promise拒绝吗?
当然,在这个例子中,你可以只使用promise.then(alert),因为你只是用和回调相同的参数调用alert,但是箭头语法更通用,让你可以这样写:
promise.then(data => alert("x is " + data.x));
并不是每个浏览器都支持这种语法,但在某些情况下,当你确定你的代码将在什么浏览器上运行时——例如,当你编写Chrome扩展,Firefox插件,或使用Electron, NW.js或AppJS的桌面应用程序时(详情见此答案)。
关于箭头函数的支持,请参见:
http://caniuse.com/#feat=arrow-functions
http://kangax.github.io/compat-table/es6/#test-arrow_functions
更新(2017)
现在有一种更新的语法,叫做async函数,它有一个新的await关键字,而不是下面的代码:
functionReturningPromise()
.then(data => console.log('Data:', data))
.catch(error => console.log('Error:', error));
让你写:
try {
let data = await functionReturningPromise();
console.log('Data:', data);
} catch (error) {
console.log('Error:', error);
}
您只能在使用async关键字创建的函数中使用它。更多信息,请参见:
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
有关浏览器的支持,请参阅:
http://caniuse.com/async-functions
有关Node中的支持,请参见:
http://node.green/#ES2017-features-async-functions
在本地不支持async和await的地方,你可以使用Babel:
https://babeljs.io/docs/plugins/transform-async-to-generator/
或者使用稍微不同的语法,比如co或Bluebird协程中的基于生成器的方法:
https://www.npmjs.com/package/co
http://bluebirdjs.com/docs/api/promise.coroutine.html
更多信息
关于承诺的其他问题:
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?