注意:此答案是在2010年2月编写的。
请参见底部2015、2016和2017年的更新。
您无法从异步函数中返回任何内容。您可以返回一个promise。我在回答以下问题时解释了jQuery中的promises工作原理:
如果您能解释为什么您想要返回数据以及稍后想要使用它做什么,那么我可能能够给您提供更具体的答案。
通常情况下,不是:
function testAjax() {
$.ajax({
url: "getvalue.php",
success: function(data) {
return data;
}
});
}
你可以像这样编写你的testAjax函数:
function testAjax() {
return $.ajax({
url: "getvalue.php"
});
}
然后你可以像这样获取你的 Promise:
var promise = testAjax()
你可以存储你的承诺,你可以传递它,你可以在函数调用中使用它作为参数,并且你可以从函数中返回它,但是当你最终想要使用由AJAX调用返回的数据时,你必须这样做:
promise.success(function (data) {
alert(data);
});
如果您的数据此时可用,那么该函数将立即被调用。如果不可用,则会在数据可用时立即调用。
所有这样做的重点是因为您在调用$.ajax后数据不会立即可用,因为它是异步的。Promises是一个很好的抽象函数,可以说:我不能返回你数据,因为我还没有它,而且我不想阻塞并让你等待,所以这里有一个承诺,稍后你就能使用它,或者只是把它给别人并完成它。
请参见此
DEMO。
更新(2015)
目前(截至2015年3月),jQuery Promises与
Promises/A+规范不兼容,这意味着它们可能与其他
Promises/A+符合实现不太协作。
但是,即将推出的版本3.x中的jQuery Promises将与Promises/A+规范兼容(感谢
Benjamin Gruenbaum指出)。当前(截至2015年5月),jQuery的稳定版本为1.x和2.x。
我在2011年3月所解释的是一种使用
jQuery Deferred Objects以异步方式执行某些操作的方法,而在同步代码中则通过返回值来实现。
但同步函数调用可以做两件事情——如果可能的话,它可以返回一个值;如果不能返回值,则会抛出异常。Promises/A+以一种几乎和同步代码中的异常处理一样强大的方式解决了这两种用例。jQuery版本可以很好地处理相当于返回值的内容,但相当于复杂异常处理的内容有些棘手。
特别是,在同步代码中异常处理的整个重点不仅在于放弃并显示友好的消息,而在于尝试修复问题并继续执行,或者可能为程序的其他部分重新抛出相同或不同的异常以进行处理。在同步代码中,您拥有一个调用堆栈。在异步调用中,您没有调用堆栈,因此根据Promises/A+规范所需的高级异常处理确实可以帮助您编写能够处理错误和异常的代码,即使是对于复杂的用例。
关于jQuery和其他实现之间的差异以及如何将jQuery promises转换为符合Promises/A+标准的内容,请参见Kris Kowal等人在Q库维基上发布的
Coming from jQuery,以及Jake Archibald在HTML5 Rocks上发布的
Promises arrive in JavaScript。
如何返回一个真正的promise?
我上面的示例中的函数:
function testAjax() {
return $.ajax({
url: "getvalue.php"
});
}
返回一个jqXHR对象,它是一个jQuery Deferred Object。
要使其返回一个真正的promise,您可以将其更改为 - 使用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()
。
要查看在没有polyfill的情况下可以使用ES6 Promises的地方,请参见:
Can I use: Promises。
有关更多信息,请参见:
jQuery的未来
从3.x版本开始(截至2015年5月,当前稳定版本为1.x和2.x),jQuery的未来版本将与Promises/A+规范兼容(感谢Benjamin Gruenbaum在评论中指出)。“我们已经决定了两个变化,即Deferred实现的Promise/A+兼容性[...]”(jQuery 3.0和Web开发的未来)。更多信息请参见:Dave Methvin的jQuery 3.0:下一代和Paul Krill的jQuery 3.0:更多互操作性,更少的Internet Explorer。
有趣的讲话
更新(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 的 rejection handlers:
当然,在此示例中,您可以仅使用 promise.then(alert)
,因为您只是使用与回调相同的参数调用 alert
,但箭头语法更通用,让您编写类似以下内容的内容:
promise.then(data => alert("x is " + data.x));
并非每个浏览器都支持此语法,但在某些情况下,您可以确定代码将在哪个浏览器上运行 - 例如编写Chrome扩展程序、Firefox插件或使用Electron、NW.js或AppJS的桌面应用程序(有关详细信息,请参见此答案)。
有关箭头函数的支持,请参见:
更新(2017年)
现在有一种全新的语法叫做异步函数,使用一个新的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
关键字创建的函数内部使用它。有关更多信息,请参见:
有关浏览器支持,请参见:
有关Node的支持,请参见:
在不支持 async
和 await
的地方,您可以使用 Babel:
或者使用稍微不同的语法,像在co
或Bluebird协程中基于生成器的方法:
更多信息
关于 Promise 的其他问题,请参阅以下详细信息: