注意:此答案写于 2010 年 2 月。
请参阅底部的 2015、2016 和 2017 年更新。
您不能从异步函数返回任何内容。你能回报的是一个Promise。我在回答这些问题时解释了 jQuery 中的 Promise 是如何工作的:
如果您可以解释为什么要返回数据以及稍后您想用它做什么,那么我可能会给您一个更具体的答案如何去做。
通常,而不是:
function testAjax() {
$.ajax({
url: "getvalue.php",
success: function(data) {
return data;
}
});
}
您可以像这样编写 testAjax 函数:
function testAjax() {
return $.ajax({
url: "getvalue.php"
});
}
然后你可以像这样得到你的Promise:
var promise = testAjax();
你可以存储你的Promise,你可以传递它,你可以在函数调用中将它用作参数,你可以从函数中返回它,但是当你最终想要使用由 AJAX 调用返回的数据时,你必须像这样做:
promise.success(function (data) {
alert(data);
});
(有关简化的语法,请参阅下面的更新。)
如果此时您的数据可用,则将立即调用此函数。如果不是,那么它将在数据可用时立即调用。
执行所有这些操作的全部意义在于,您的数据在调用 $.ajax 后不会立即可用,因为它是异步的。Promises 是函数的一个很好的抽象,可以说:我无法返回数据,因为我还没有它,而且我不想阻塞并让你等待,所以这里是一个Promise,你将能够稍后使用它,或者只是将它交给其他人并完成它。
看到这个演示。
更新 (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+ 规范的要求在 Promise 内部进行高级异常处理,这确实可以帮助您编写代码,即使对于复杂的用例,也能以有意义的方式处理错误和异常。
有关 jQuery 和其他实现之间的差异,以及如何将 jQuery Promise转换为 Promises/A+ 兼容,请参阅Kris Kowal 等人的来自 jQuery。在 Q 库 wiki 上,Promises在 HTML5 Rocks 上由 Jake Archibald在 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(...))
也是module文档中解释的promise
内容,它应该适用于ES6Promise.resolve()
。
今天要使用 ES6 Promises,您可以使用Jake Archibald 的es6-promise modulepolyfill()
。
要查看在没有 polyfill 的情况下可以在何处使用 ES6 Promises,请参阅:Can I use: Promises。
有关更多信息,请参阅:
jQuery 的未来
jQuery 的未来版本(从 3.x 开始 - 截至 2015 年 5 月的当前稳定版本是 1.x 和 2.x)将与Promises/A+ 规范兼容(感谢Benjamin Gruenbaum在评论中指出)。“我们已经决定的两个变化是我们的延迟实现的 Promise/A+ 兼容性 [...]”(jQuery 3.0 和 Web 开发的未来)。有关更多信息,请参阅:jQuery 3.0: Dave Methvin 的下一代和jQuery 3.0: Paul Krill 的更多互操作性,更少的 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的拒绝处理程序:
当然,在这个例子中,你可以使用,promise.then(alert)
因为你只是alert
使用与回调相同的参数进行调用,但箭头语法更通用,可以让你编写如下内容:
promise.then(data => alert("x is " + data.x));
并非每个浏览器都支持这种语法,但在某些情况下,您可以确定代码将在哪个浏览器上运行 - 例如,在编写Chrome 扩展程序、Firefox 插件或使用 Electron、NW.js 或AppJS(有关详细信息,请参阅此答案)。
有关箭头函数的支持,请参阅:
更新 (2017)
现在有一种更新的语法称为 async 函数,它带有一个 newawait
关键字,而不是以下代码:
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:
或者使用稍微不同的语法基于生成器的方法,例如 inco
或 Bluebird 协程:
更多信息
有关 promise 的其他一些问题以获取更多详细信息: