JavaScript 中的 observable 和 promises 之间有什么区别?

What are the differences between observables and promises in JavaScript?

所以我读到,在一些即将推出的 JavaScript MVC 中,可观察对象正在寻求在使用方面超越承诺:

observables 和 promises 有什么区别?

更新:抱歉!删除了我的虚假声明。

What is the difference between observables and promises?

简单地说:一个 promise 异步解析为一个 单个 值,一个 observable 异步解析(或发出)多个 值(超过时间)。

具体例子:

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

可在此处找到更多信息:http://reactivex.io/intro.html

i've read that observables are looking to overtake promises

不太可能。 Observables 可能是某些问题的更好解决方案,但这并没有使承诺过时(如果那是你的意思)。

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

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

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

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

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

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

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

-支持处理Timeouts/Error处理。假设我们的 HTTP 请求失败,Rx 允许我们轻松地 重试 发出请求。

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

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

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

总而言之,Rx 可以做的一切都比 Promises 可以做,而且远不止于此。我怀疑在接下来的几年里,将继续转向 Rx 而不是 Promises。

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

Angular 2 guid

中所述

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

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

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

A request-cancel-new-request sequence is difficult to implement with Promises, but easy with Observables.

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

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

Observable 是声明性的;计算直到订阅才开始。 Promise 在创建时立即执行。这使得 observables 对于定义食谱很有用,只要您需要结果,就可以 运行。

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

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

Observables subscribe() 负责处理错误。承诺将错误推送给子承诺。这使得 observables 对于集中和可预测的错误处理很有用。

官方网站angular的最佳解释:

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

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

揭开复杂概念神秘面纱的最好方法是从头开始实施它。这是一个几乎纯功能性的 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);

在上面的示例中,Observable squaredNumStream 异步发出理论上无限值的流。您不能对 Promise 执行此操作,因为它们代表单个未来值。

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

squaredNumStream 在声明时不会 运行,但仅在订阅后才会,因为 Observable 是延迟计算的。另一方面,Promises 是急切求值的,也就是说,它们会在您创建它们后立即开始 运行ning。

最后,Observable 可以通过设计取消,而 Promise 由于存在单播语义,因此很难取消。

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

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

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