【问题标题】:What are the differences between observables and promises in JavaScript?JavaScript 中的 observable 和 Promise 有什么区别?
【发布时间】:2016-07-04 00:32:33
【问题描述】:

所以我了解到,在一些即将推出的 JavaScript MVC 中,observables 正在寻求超越 Promise:

可观察对象和承诺有什么区别?

更新:抱歉!删除了我的虚假陈述。

【问题讨论】:

  • 您介意分享您阅读本文的来源吗?我个人从未听说过除 Object.observe 之外的可观察对象,它已从规范中删除,与 Promises 无关
  • 或者你说的是Proxies
  • 承诺:单值,异步。可观察的:集合,异步。请参阅 reactivex.io/intro.html 作为 Observable 提案的实现。
  • 我猜这个问题被否决了,因为这个问题有点开放式 + 没有支持你的开场白的来源(谷歌快速搜索告诉我 observables 没有制作下一个 ecmascript )。无论如何:promise 和 observables 只是设计模式,但我认为 observables 比 promises 更有用,尤其是使用 Reactive Extensions(参见 github.com/ReactiveX/RxJSreactivemanifesto.org

标签: javascript promise es6-promise


【解决方案1】:

可观察对象和承诺有什么区别?

简单地说:promise 异步解析为 单个 值,observable 异步解析(或发出)多个 值(随着时间的推移)。

具体例子:

  • Promise:来自 Ajax 调用的响应
  • 可观察:点击事件

更多信息可以在这里找到:http://reactivex.io/intro.html

我了解到 observables 正在寻求超越承诺

不太可能。 Observables 可能是解决某些问题的更好解决方案,但这并不会使 Promise 过时(如果这就是你的意思的话)。

【讨论】:

  • 哇,这根本不是什么大的差异——在错误处理、调度和模型方面存在巨大差异。 Promise 是一个单个值,而 observable 就像一个函数,可以调用它来产生多个值。一个承诺总是被缓存和多播 - 一个可观察的是单播的。如果 ajax 调用的 observable 有两个订阅者 - 每个订阅者(除非使用组合器)都会创建一个单独的 HTTP 调用。
  • @BenjaminGruenbaum 我认为可以公平地说,这个答案主要区别在于你的评论表明了细微差别。
【解决方案2】:

Promise 代表 1 个未来值。 Observables 是可能无限数量的值的表示。

Promises 将在创建后立即触发对该值的获取。 Observables 只会在您订阅它们时开始产生值。 (除非它是一个热门的可观察对象,但这超出了这个问题的范围)

Promise 旨在表示 AJAX 调用。 Observables 旨在表示任何事物:事件、来自数据库的数据、来自 ajax 调用的数据、(可能是无限的)序列等。

【讨论】:

    【解决方案3】:

    Promises 提供了一种非常简单的回调机制,而 Rx 提供了对异步编程的强大抽象。 Observable 表示一个数据流,然后我们可以对其应用运算符来定义应如何处理传入的数据。

    如果您只需要发出 HTTP 请求,然后更新 UI 组件,那么使用 Promise 就足够了。

    但是,大多数应用的需求往往比这更复杂(即使一开始并不明显)。以我们的 HTTP 请求为例,让我们看看如何将其建模为 Observable 并使用一些 Rx 运算符可以帮助我们:

    -如果 HTTP 请求是由用户操作触发的,我们可能要警惕触发多个 HTTP 请求(想象用户在搜索框中键入内容)。我们不希望每次击键都触发请求,因此我们可能希望限制我们的搜索,以便仅在用户停止输入 300 毫秒时触发请求。此外,如果用户键入一个单词,等待 300 毫秒,然后添加另一个字符,我们将触发后续 HTTP 请求。使用 Promises,我们可能会遇到竞争条件,因为我们无法控制接收响应的顺序,也无法取消旧请求。 Rx 通过允许我们在流之间切换 来解决这个问题,这会在我们不再关心的旧请求订阅上调用 Dispose。我们还可能过滤掉任何无效的搜索输入,例如 Where 搜索词的长度小于 3 个字符。

    -支持处理超时/错误处理。假设我们的 HTTP 请求失败,Rx 允许我们轻松重试发出请求。

    -假设我们的应用程序的几个部分需要进行相同的 HTTP 调用,我们可能不希望实际进行多次调用。我们可以将我们的 observable 暴露给多个消费者,并使用 Replay 来确保调用一次并为后续订阅者缓存结果。我们甚至可以为 Replay 提供 TimeSpan,为我们提供过期的缓存行为。

    -通过使用调度程序对线程进行强大的抽象,这使我们能够控制并发性。更好的是,我们可以在单元测试中使用测试调度器来控制时间,允许我们模拟超时、竞争条件等。

    这些是一些简单的例子来展示什么是可能的。 Rx 框架中有更多的运算符来满足所有类型的场景,并且 Rx 的可组合性意味着您可以轻松地组合运算符来定义您需要的行为。创建自己的可重用运算符(例如 RetryAfterDelay)也很容易。

    总而言之,Rx 可以做的所有事情都比 Promises 做的要多得多。我怀疑在接下来的几年里,会继续转向 Rx 而不是 Promises。

    如需进一步阅读,我建议您查看Angular 2 guide 中关于 Observables 的部分。

    【讨论】:

      【解决方案4】:

      正如Angular 2 guid中所说的

      当您想要获取单个数据块时,转换为 Promise 通常是一个不错的选择。所以当你收到数据时,你就完成了。

      但在某些情况下,请求并不总是只执行一次。您可以启动一个请求,取消它,然后在服务器启动之前发出另一个请求 响应了第一个请求。

      例如在搜索组件中 当用户在搜索框中键入名称时,您将通过该搜索查询发出重复的 HTTP 请求。

      request-cancel-new-request 序列很难用 Promise,但使用 Observables 很容易。

      因此,如果您的组件仅通过一个请求获取数据,则使用 Promise 是一个不错的选择,但如果它有一系列 request-cancel-new 请求,则应使用 observable

      【讨论】:

        【解决方案5】:

        Observables 经常被比作 Promise。以下是一些主要区别:

        Observables 是声明性的;直到订阅才开始计算。 Promise 在创建时立即执行。这使得 observables 对于定义可以在需要结果时运行的配方非常有用。

        Observables 提供了许多值。承诺提供了一个。这使得 observables 对于随着时间的推移获取多个值很有用。

        Observable 区分链接和订阅。 Promise 只有 .then() 子句。这使得 observables 可用于创建复杂的转换配方以供系统的其他部分使用,而不会导致工作被执行。

        Observables subscribe() 负责处理错误。 Promise 将错误推送到子 Promise。这使得 observables 对于集中和可预测的错误处理非常有用。

        官方网站上最好的角度解释:

        https://angular.io/guide/comparing-observables

        【讨论】:

          【解决方案6】:

          当您正确理解Observables 时,与Promises 的区别非常明显。

          揭开复杂概念的神秘面纱的最佳方法是从头开始实施它。这是一个几乎纯功能的Observable 实现和一个示例,它不适用于Promises:

          /*** Observable type ***/
          
          // type constructor (of a product type)
          
          const proType = name => cons => {
            const f = (k, ...args) =>
              Object.defineProperties({["run" + name]: k}, {
                [Symbol.toStringTag]: {value: name},
                [Symbol("args")]: {value: args}
              });
          
            return cons(f);
          };
          
          // value constructor
          
          const Observable = proType("Observable")
            (Observable => k => Observable(k));
          
          /*** Observer factory ***/
          
          const Observer = observer => {
            let isUnsubscribed = false;
          
            return {
              next: function(x) {
                if (isUnsubscribed)
                  throw new Error("unsubscribed");
          
                else {
                  try {
                    return observer.next(x);
                  }
          
                  catch(e) {
                    isUnsubscribed = true;
                    this.cancel();
                    throw e;
                  }
                }
              },
          
              error: function(e) {
                if (isUnsubscribed)
                  throw new Error("unsubscribed");
          
                else {
                  try {
                    return observer.error(e);
                  }
          
                  catch(e_) {
                    isUnsubscribed = true;
                    this.cancel();
                    throw e_;
                  }
                }
              },
          
              complete: function() {
                if (isUnsubscribed)
                  throw new Error("unsubscribed");
          
                else {
                  try {
                    const r = observer.complete();
                    this.cancel();
                    return r;
                  }
          
                  catch(e) {
                    isUnsubscribed = true;
                    cancel();
                    throw e;
                  }
                }
              }
            };
          };
          
          /*** combinators + auxiliary functions ***/
          
          const subscribe = observable => handlers => {
            const observer = Observer(handlers),
              cancel = observable.runObservable(observer);
          
            observer.cancel = cancel;
            return cancel;
          };
          
          const obsMap = f => observable =>
            Observable(observer => {
              const mapObserver = {
                next: x => observer.next(f(x)),
                error: e => observer.error(e),
                complete: () => observer.complete()
              };
          
              return observable.runObservable(mapObserver);
            });
          
          /*** main ***/
          
          // create an Observable instance
          
          const numStream = Observable(observer => {
            let i = 0;
          
            const timer = setInterval(() => {
              observer.next(i++);
            }, 1000);
            
            return () => clearTimeout(timer);
          });
          
          // map a function over it
          
          const squaredNumStream =
            obsMap(x => x * x) (numStream);
          
          // run the observable
          
          const cancel = subscribe(squaredNumStream) ({
            next: x => console.log(x),
            error: e => console.error(e),
            complete: () => console.log("finished")
          });
          
          // cancel it
          
          setTimeout(cancel, 11000);

          在上面的示例中,ObservablesquaredNumStream 异步发出理论上无限值的流。 Promises 不能这样做,因为它们代表一个单一的未来值。

          我本可以轻松订阅另一个squaredNumStream,而两个实例不会相互干扰。这是因为Observables 是单播,而Promises 是多播。

          squaredNumStream 不会在声明时运行,而只会在订阅后运行,因为 Observables 会被延迟评估。另一方面,Promises 会受到热切评估,也就是说,它们会在您创建它们后立即开始运行。

          最后,Observables 可以通过设计取消,而 Promises 由于存在单播语义而难以取消。

          【讨论】:

            【解决方案7】:

            Observables VS。承诺(杰里米·维尔肯)

            除了新语法之外,observables 是 JavaScript 应用程序的新模式 管理异步活动。它们也是在 JavaScript 语言中原生实现的功能的草案,因此它在模式背后具有重要意义。 RxJS 是 我们将使用库来帮助我们在应用程序中实现可观察对象。

            Promises 是另一种有助于处理异步调用的构造,它很有用 例如,用于发出 API 请求。 Promise 有一个主要的限制,因为它们是 仅对一个调用周期有用。例如,如果你想让一个 Promise 返回一个 像用户点击这样的事件的价值,该承诺将在第一次点击时解决。但是您可能对处理每个用户点击操作感兴趣。通常,你会使用一个事件 监听器,它允许您随着时间的推移处理事件。这是一个重要的区别:Observables 就像事件处理程序一样,它们继续处理数据 时间并允许您持续处理该数据流。

            【讨论】:

              猜你喜欢
              • 2016-09-18
              • 2017-02-06
              • 2011-11-30
              • 2019-01-20
              • 2018-05-12
              • 1970-01-01
              • 1970-01-01
              • 2016-12-03
              • 2019-12-11
              相关资源
              最近更新 更多