JavaScript中的Deferred,Promise和Future之间有什么区别?


300

递延,承诺和期货之间有什么区别?
这三者之间是否有公认的理论?


11
我认为这与jQuery
无关


8
我本人还没有使用过它们,但是这是Wikipedia上的一个不错的介绍en.wikipedia.org/wiki/Futures_and_promises。虽然我没有完全正确地理解用例。在异步事件驱动的语言(如javascript)中。乍一看,我看不到它们提供了比回调更多的东西,除了更干净的API。如果有人可以提供示例用例,并演示如何应用这些概念,以及为什么回调将是效率低下的解决方案,我将非常喜欢。@duri这与jQuery无关。可以删除jQuery标签吗?
AshHeskes,2011年

2
@ jfriend00很棒的链接,应该可以作为答案。
fncomp

Answers:


97

考虑到我对尝试回答OP的问题的明显不满。字面上的答案是,诺言是与其他对象共享的东西,而延期应保持私有。首先,延期(通常扩展为Promise)可以解决自己,而Promise可能无法解决。

如果您对细节有兴趣,请检查Promises / A +


据我所知,总体目的是提高清晰度并通过标准化接口放松耦合。请参阅@ jfriend00的建议阅读内容:

使用promise而不是直接将回调传递给函数(可以导致接口紧密耦合),而是使用promise可以将对同步或异步代码的关注分开。

就个人而言,我发现在处理例如由异步请求填充的模板,加载具有依赖性网络的脚本以及以非阻塞方式提供用户反馈以形成数据时,延迟特别有用。

确实,比较以异步方式在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.");
   };
});

对于promise制定的版本(再次抱歉,我在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.");
   });
});

对半伪代码表示歉意,但我希望它可以使核心思想更加清晰。基本上,通过返回标准化的承诺,您可以传递承诺,从而可以进行更清晰的分组。


10
尽管此答案可能有用,但实际上并没有解决这个问题:取决于实现方式,所谓的递延是期货或承诺。
awdz9nld 2012年

@MartinKällman你是对的!我已经有一段时间没有再研究过,并且学到了一些东西。我将在下面发布一个单独的答案,但请保留此答案,因为人们似乎已经从使用示例中受益。
fncomp 2012年

@MartinKällman,考虑写一个新答案。但是,我认为OP实际上想知道Promises and Deferreds的用途。对于他的实际问题,答案大概是:“递延者可以解决自己的问题。AFAIK,应允和递延背后的理论来自[Functional Reactive Programming | haskell.org/haskellwiki/Functional_Reactive_Programming],这是一种使回调变平坦的技术。 ”。
fncomp

2
这完全是错误的,您的示例与回调一样容易实现。承诺不是关于回调聚合和解耦,而是提供一个DSL来编写异步代码(如已编写的同步代码)。特别fn(callback, errback)是它并没有比它更紧密地耦合或没有那么有用了fn().then(callback, errback),但是无论如何,这都是错误的使用诺言的方式。我尤其讨厌货运狂热的$.when例子-绝对没有理由不能使用可$.when用于回调的函数。
Esailija

尽管+1无法回答这个问题,但我可以知道回调地狱是什么。
Bhojendra Rauniyar 2015年

146

这些答案,包括所选择的答案,是良好的概念引入的承诺,但在细节缺乏究竟差别在使用图书馆实现它们(还有时出现的术语 重要的区别)。

由于它仍然是一个不断发展的规范,因此当前的答案来自尝试调查引用(例如Wikipedia)和实现(例如jQuery):

  • 递延的:从未在流行的参考文献1 2 3 4中描述过, 但通常被实现用作诺言解析(实现和)的仲裁器。 5 6 7 resolvereject

    有时,递延也是promise(实现then),而在 其他5到6次中,仅Deferred才具有解析能力,并迫使用户访问使用的Promise更为纯净。 7 then

  • 承诺:正在讨论的策略中最引人入胜的词。

    一个代理对象,它存储目标函数的结果,我们希望对其进行抽象化,并公开一个then接受另一个目标函数并返回新诺言的函数。 2

    来自CommonJS的示例:

    > asyncComputeTheAnswerToEverything()
        .then(addTwo)
        .then(printResult);
    44

     

    始终在大众参考文献中进行描述,尽管从未明确说明其责任解决方案属于谁。 1 2 3 4

    始终存在于流行的实现中,并且从未提供解决方案的能力。 5 6 7

  • 未来:在一些流行的参考文献1 和至少一个流行的实现8中 似乎已被弃用的术语 , 但似乎已被淘汰,而不再是“承诺”一词 3, 并且在该主题的引言中并不总是提及。 9

    但是,至少一个库在不提供then功能的情况下,通常将该术语用于抽象化同步和错误处理。 10 目前尚不清楚是否有意避免使用“承诺”一词,但这可能是一个不错的选择,因为承诺是围绕“ thenables”建立的。 2

参考文献

  1. 关于承诺和未来的维基百科
  2. 承诺/ A +规范
  3. DOM承诺标准
  4. DOM标准承诺规范WIP
  5. DOJO工具包延迟
  6. jQuery Deferreds
  7. FutureJS
  8. 关于承诺的功能性Javascript部分
  9. AngularJS集成测试中的期货

杂乱无章的事物


5
为了进一步澄清“未来”一词,期货在许多编程语言中都有很长的历史,其历史可以追溯到80年代中期。如今,该术语仍在广泛使用,尤其是在JVM上。JavaScript似乎选择使用术语“ Promise”来表示类似于Java的“ Future”所表示的意思。Scala将相同的概念分为“ Future”和“ Promise”,以引用JavaScript程序员称为Promise的“读取”句柄和“写入”句柄。
希瑟·米勒

1
当然,微软必须为此制定自己的术语,因此在C#中它们被称为Task
BlueRaja-Danny Pflughoeft

72

真正使这一切的点击对我来说是这样介绍的Domenic Denicola。

github要点中,他给出了我最喜欢的描述,这非常简洁:

许诺的要点是使我们在异步世界中恢复功能组合和错误冒泡。

换句话说,承诺是一种方式,让我们编写异步代码,几乎是一样容易写,如果它是同步的

考虑以下示例,并附带以下承诺:

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 1.8.2中,jQuery中的Promise实现已损坏(请参见要点)。
它据说实现了Promises / A thenables,但是在整个“异步try / catch”功能无法正常工作的意义上,您没有得到应有的正确错误处理。遗憾的是,因为使用异步代码进行“尝试/捕获”非常酷。

如果你要使用的承诺(你应该尝试他们用自己的代码!),用克里斯科瓦尔Q值。jQuery版本只是一些用于编写更简洁的jQuery代码的回调聚合器,但没有指出重点。

关于Future,我不知道,在任何API中都没有看到。

编辑: Domenic Denicola在YouTube上关于@Farm的评论的承诺演讲

视频中迈克尔·杰克逊(Michael Jackson)的话:

我希望您能记住这句话: 诺言是异步值

这是一个很好的描述:承诺就像来自未来的变量-对某个事物在某些时候将存在(或发生)的一流参考。


5
W3和Chrome核心团队的成员对Future(现在已在DOM中实现!)进行了很好的解释:xanthir.com/b4PY0
oligofren

1
@oligofren感谢您的链接,这看起来不错!顺便说一句,多么令人讨厌的Favicon大声笑。
卡米洛·马丁

1
这个答案需要更多的支持。它的投票应高于IMO接受的答案。
Chev

1
Domenic Denicola在youtube上关于Promises的演讲:youtube.com/watch?
农场

@农大!我将其添加到答案中。
卡米洛·马丁

32

一个Promise代表一个在创建Promise时不一定知道的值的代理。它允许您将处理程序与异步操作的最终成功值或失败原因相关联。这使异步方法可以像同步方法一样返回值:异步方法返回最终值,而不是最终值。

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise

deferred.promise()方法允许异步功能防止其他代码干扰其内部请求的进度或状态。Promise仅公开附加其他处理程序或确定状态(然后,完成,失败,总是,管道,进度,状态和 Promise)所需的Deferred方法,但不公开更改状态的方法(resolve,reject,notify,resolveWith, rejectWith和notifyWith)。

如果提供了target,deferred.promise()则将方法附加到其上,然后返回该对象而不是创建一个新对象。这对于将Promise行为附加到已存在的对象很有用。

如果要创建延迟,请保留对延迟的引用,以便在某个时候可以解决或拒绝该延迟。通过deferred.promise()仅返回Promise对象,以便其他代码可以注册回调或检查当前状态。

可以简单地说,Promise表示一个尚不知道的值,而Deferred表示尚未完成的工作。


在此处输入图片说明


1
图表表示形式加1。布拉维西莫!^ _ ^
Ashok MA,

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.