JavaScript 中的 Deferred、Promise 和 Future 有什么区别?
-
22-10-2019 - |
题
延期、承诺和期货之间有什么区别?
这三个背后是否有一个普遍认可的理论?
解决方案
鉴于我对我如何试图回答OP的问题的不喜欢。字面上的答案是,承诺是带有其他对象共享的东西,而延期应保持私密。首先,递延(通常会延伸承诺)可以解决自己,而诺言可能无法做到。
如果您对细节感兴趣,请检查 承诺/a+.
据我所知,总体目的是提高清晰度并通过标准化界面松开耦合。看 建议阅读 来自 @jfriend00:
与其将回调直接传递给函数,而是可以通过承诺将紧密耦合接口的某些东西传递到紧密耦合的接口,这使人们可以分开对同步或异步的代码的关注点。
就个人而言,我发现在处理由异步请求填充的EG模板时,我发现递延特别有用,加载具有依赖性网络的脚本以及提供用户反馈以非阻滞方式形成数据。
实际上,比较在JS模式下加载CodeMirror后做某事的纯回调形式(歉意,我没有在A中使用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.");
});
});
对于半韧带代码表示歉意,但我希望这使核心想法有些清楚。基本上,通过返回标准化的承诺,您可以通过承诺,从而可以进行更清晰的分组。
其他提示
这些答案,包括选定的答案,非常适合从概念上介绍承诺,但缺乏详细信息的细节,在使用实施图书馆时,术语中出现的差异到底是什么(并且是 重要差异)。
因为它仍然 不断发展的规范, ,答案目前来自试图调查这两种参考(例如 维基百科)和实现(例如 jQuery):
延期: :从未在流行参考中描述, 1 2 3 4 但实施通常用作承诺解决的仲裁者(实施
resolve
和reject
). 5 6 7有时延期也是承诺(实施
then
), 5 6 其他时候,只有延期才能解决并迫使用户访问使用的承诺,这是更纯粹的then
. 7承诺: :针对正在讨论的策略中最无所不包的词。
存储目标函数结果的代理对象,我们想抽象其同步性,并展示一个
then
功能接受另一个目标功能并返回新的承诺。 2示例来自 commonjs:
> asyncComputeTheAnswerToEverything() .then(addTwo) .then(printResult); 44
未来: :在一些流行的参考文献中发现了一个看似弃用的术语 1 至少一个受欢迎的实现, 8 但是似乎被逐步淘汰了讨论,而是偏爱“承诺”一词 3 并非总是在对该主题的流行介绍中提到。 9
但是,至少一个库使用该术语通常用于抽象同步性和错误处理,而不提供
then
功能。 10 目前尚不清楚避免“承诺”一词是故意的,但可能是一个不错的选择,因为承诺是围绕“当时的”而建立的。 2
参考
- 维基百科关于承诺和未来的
- 承诺/A+规格
- DOM标准诺言
- DOM标准承诺规格WIP
- Dojo工具包推迟
- jQuery延期
- 问
- 未来
- 关于承诺的功能性JavaScript部分
- Angularjs集成测试中的期货
杂志可能会混淆事物
-
(tl; dr,承诺/a+主要解决承诺/a的歧义)
真正让我咔嗒声的是 这个演示文稿 由Domenic Denicola。
在一个 Github Gist, ,他给出了我最喜欢的描述,这很简洁:
承诺的目的是让我们回到异步世界中的功能组成和错误冒泡。
换句话说,承诺是一种让我们写作的方式 异步 代码几乎就像写的代码一样容易 同步.
考虑一下这个示例,并承诺:
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);
}
(如果这听起来仍然很复杂,请观看演示文稿!)
关于递延,这是一种方法 .resolve()
或者 .reject()
承诺。在里面 承诺/b 规格,称为 .defer()
. 。在jQuery中,是 $.Deferred()
.
请注意,据我所知,JQuery中的承诺实施已被打破(请参阅该要点),至少在JQuery 1.8.2时。
据说它实现了 承诺/A当, ,但是您没有得到正确的错误处理,从某种意义上说,整个“ async try/catch”功能无法正常工作。可惜,因为使用异步代码进行“尝试/捕捉”非常酷。
如果您要使用承诺(应该使用自己的代码尝试一下!),请使用 克里斯·科瓦尔(Kris Kowal)的Q. 。 jQuery版本只是编写清洁器jQuery代码的一些回调聚合器,但错过了重点。
关于未来,我不知道,我还没有在任何API中看到过。
编辑: Domenic Denicola的YouTube关于承诺的讨论 从 @农场下面的评论。
迈克尔·杰克逊(Michael Jackson)的话(是的, 迈克尔杰克逊)从视频中:
我要你在脑海中燃烧这个短语: 承诺是 异步值.
这是一个很好的描述:一个承诺就像未来的变量一样 - 一流的引用,即某个时候(或发生)。
A 承诺 代表创建 Promise 时不一定知道的值的代理。它允许您将处理程序与异步操作的最终成功值或失败原因相关联。这使得异步方法可以像同步方法一样返回值:异步方法返回一个在未来某个时刻具有值的承诺,而不是最终值。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
这 deferred.promise()
方法允许异步函数防止其他代码干扰其内部请求的进度或状态。Promise 仅公开附加附加处理程序或确定状态所需的 Deferred 方法(然后、完成、失败、总是、管道、进度、状态和承诺),但不会改变状态(解决、拒绝、通知、resolveWith、rejectWith 和 notifyWith).
如果提供了目标, deferred.promise()
会将方法附加到其上,然后返回该对象,而不是创建一个新对象。这对于将 Promise 行为附加到已存在的对象非常有用。
如果您要创建延迟对象,请保留对延迟对象的引用,以便可以在某个时候解决或拒绝它。通过 deferred.promise() 仅返回 Promise 对象,以便其他代码可以注册回调或检查当前状态。
简单地说,我们可以说 承诺 表示一个尚不知道的值 延期 代表尚未完成的工作。
- 一个
promise
代表尚不清楚的价值 - 一个
deferred
代表尚未完成的工作
承诺是最初未知的结果的占位符,而递延表示导致值的计算。
参考