Deferreds、Promises 和 Futures 之间有什么区别?
这三者背后是否有普遍认可的理论?
JavaScript 中的 Deferred、Promise 和 Future 之间有什么区别?
这些答案,包括所选择的答案,是良好的概念引入的承诺,但在细节缺乏究竟差别在使用图书馆实现它们(还有时出现的术语 是重要的区别)。
由于它仍然是一个不断发展的规范,因此目前的答案来自尝试调查参考资料(如wikipedia)和实现(如jQuery):
Deferred:从未在流行参考文献1 2 3 4 中描述, 但通常被实现用作承诺解析的仲裁者(实现和)。 5 6 7
resolve
reject
有时 deferred 也是承诺(实现
then
), 5 6 其他时候,让 Deferred 只能够解析并强制用户访问使用承诺被认为更纯粹。 7then
承诺:所讨论的战略最全面的词。
一个代理对象存储我们想要抽象其同步性的目标函数的结果,并暴露一个
then
接受另一个目标函数并返回一个新承诺的函数。 2来自CommonJS 的示例:
> asyncComputeTheAnswerToEverything() .then(addTwo) .then(printResult); 44
Future:在一些流行的参考文献1 和至少一个流行的实现中 发现的看似已弃用的术语 8, 但似乎已逐渐退出讨论,而倾向于使用术语“承诺” 3, 并且在该主题的流行介绍中并不总是提及。 9
然而,至少有一个库使用该术语来概括同步性和错误处理,但不提供
then
功能。 10 目前尚不清楚避免使用“承诺”一词是否是有意的,但可能是一个不错的选择,因为承诺是围绕“thenables”构建的。 2
参考
- 关于承诺和期货的维基百科
- 承诺/A+ 规格
- 关于 Promise 的 DOM 标准
- DOM 标准承诺规范 WIP
- DOJO 工具包延期
- jQuery 延迟
- 问
- FutureJS
- 关于 Promises 的功能性 Javascript 部分
- AngularJS 集成测试中的未来
杂项可能令人困惑的事情
-
(TL;DR,Promises/A+ 主要解决 Promises/A 中的歧义)
鉴于我显然不喜欢我试图回答 OP 的问题。字面的答案是,promise 是与其他对象共享的东西,而 deferred 应该保密。首先,延迟(通常扩展 Promise)可以自行解决,而 Promise 可能无法这样做。
如果您对细节感兴趣,请查看Promises/A+。
据我所知,首要目的是通过标准化接口提高清晰度和松散耦合。请参阅@jfriend00 的建议阅读:
不是直接将回调传递给函数,这会导致紧密耦合的接口,使用 Promise 允许人们分离同步或异步代码的关注点。
就我个人而言,我发现 deferred 在处理例如由异步请求填充的模板、加载具有依赖网络的脚本以及以非阻塞方式提供用户反馈以形成数据时特别有用。
确实,比较一下在 JS 模式下异步加载 CodeMirror 之后做某事的纯回调形式(抱歉,我已经有一段时间没有使用 jQuery 了):
/* assume getScript has signature like: function (path, callback, context)
and listens to onload && onreadystatechange */
$(function () {
getScript('path/to/CodeMirror', getJSMode);
// onreadystate is not reliable for callback args.
function getJSMode() {
getScript('path/to/CodeMirror/mode/javascript/javascript.js',
ourAwesomeScript);
};
function ourAwesomeScript() {
console.log("CodeMirror is awesome, but I'm too impatient.");
};
});
对于承诺制定的版本(再次道歉,我不是最新的 jQuery):
/* Assume getScript returns a promise object */
$(function () {
$.when(
getScript('path/to/CodeMirror'),
getScript('path/to/CodeMirror/mode/javascript/javascript.js')
).then(function () {
console.log("CodeMirror is awesome, but I'm too impatient.");
});
});
为半伪代码道歉,但我希望它使核心思想有些清晰。基本上,通过返回标准化的承诺,您可以传递承诺,从而允许更清晰的分组。
真正让我大吃一惊的是 Domenic Denicola 的这个演讲。
在一个github gist中,他给出了我最喜欢的描述,非常简洁:
promises 的重点是让我们返回异步世界中的函数组合和错误冒泡。
换句话说,承诺是一种方式,让我们编写异步代码,几乎是一样容易写,如果它是同步的。
考虑这个带有承诺的例子:
getTweetsFor("domenic") // promise-returning async function
.then(function (tweets) {
var shortUrls = parseTweetsForUrls(tweets);
var mostRecentShortUrl = shortUrls[0];
return expandUrlUsingTwitterApi(mostRecentShortUrl); // promise-returning async function
})
.then(doHttpRequest) // promise-returning async function
.then(
function (responseBody) {
console.log("Most recent link text:", responseBody);
},
function (error) {
console.error("Error with the twitterverse:", error);
}
);
它就像您正在编写此同步代码一样工作:
try {
var tweets = getTweetsFor("domenic"); // blocking
var shortUrls = parseTweetsForUrls(tweets);
var mostRecentShortUrl = shortUrls[0];
var responseBody = doHttpRequest(expandUrlUsingTwitterApi(mostRecentShortUrl)); // blocking x 2
console.log("Most recent link text:", responseBody);
} catch (error) {
console.error("Error with the twitterverse: ", error);
}
(如果这听起来仍然很复杂,请观看该演示文稿!)
关于 Deferred,它是一种方式.resolve()
或.reject()
承诺。在Promises/B规范中,它被称为.defer()
. 在 jQuery 中,它是$.Deferred()
.
请注意,据我所知,jQuery 中的 Promise 实现已损坏(请参阅该要点),至少从 jQuery 1.8.2 开始。
它应该实现Promises/A thenables,但是您没有得到正确的错误处理,因为整个“异步 try/catch”功能将不起作用。这很遗憾,因为使用异步代码进行“try/catch”非常酷。
如果您打算使用 Promises(您应该用您自己的代码尝试它们!),请使用Kris Kowal 的 Q。jQuery 版本只是一些回调聚合器,用于编写更清晰的 jQuery 代码,但没有抓住重点。
关于 Future,我不知道,我还没有在任何 API 中看到过。
编辑: 多梅尼克·丹尼科拉 (Domenic Denicola) 在 youtube 上关于承诺的谈话来自@Farm下面的评论。
视频中迈克尔·杰克逊(是的,迈克尔·杰克逊)的引述:
我想让你把这句话铭记在心: A promise is an asynchronous value。
这是一个很好的描述:promise 就像来自未来的变量 - 对在某些时候将存在(或发生)的事物的一流引用。
一个承诺代表某个值的代理创建承诺时未必知道。它允许您将处理程序与异步操作的最终成功值或失败原因相关联。这让异步方法可以像同步方法一样返回值:异步方法返回的不是最终值,而是在未来某个时间点具有值的承诺。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
该deferred.promise()
方法允许异步函数防止其他代码干扰其内部请求的进度或状态。Promise 仅公开附加处理程序或确定状态(then、done、fail、always、pipe、progress、state 和 promise)所需的 Deferred 方法,而不公开更改状态的方法(resolve、reject、notify、resolveWith、 rejectWith 和 notifyWith )。
如果提供了目标,deferred.promise()
则将方法附加到其上,然后返回此对象而不是创建一个新对象。这对于将 Promise 行为附加到已经存在的对象很有用。
如果您正在创建一个 Deferred,请保留对 Deferred 的引用,以便在某个时候可以解决或拒绝它。通过 deferred.promise() 仅返回 Promise 对象,以便其他代码可以注册回调或检查当前状态。
简单地说,一个Promise代表一个未知的值,而一个Deferred代表尚未完成的工作。
- A
promise
代表一个未知的值 - A
deferred
代表尚未完成的工作
promise 是最初未知的结果的占位符,而 deferred 表示产生该值的计算。
参考