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

时间:2016-03-17 15:00:11

标签: javascript promise es6-promise

所以我已经读到,在一些即将推出的JavaScript MVC中,observables正在寻求超越承诺:

观察与承诺之间有什么区别?

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

7 个答案:

答案 0 :(得分:35)

承诺是未来价值的代表。 可观察量是可能无限量的值的表示。

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

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

答案 1 :(得分:33)

  

观察与承诺之间有什么区别?

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

具体例子:

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

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

  

我读过,观察者正在寻求超越承诺

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

答案 2 :(得分:24)

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

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

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

- 如果HTTP请求是由用户操作触发的,我们可能需要警惕触发多个HTTP请求(假设用户在搜索框中键入内容)。我们不想针对每次击键发出请求,因此我们可能希望 Throttle 我们的搜索,这样我们只会在用户停止输入300ms时触发请求。此外,如果用户键入一个单词,等待300毫秒,并添加另一个字符,我们将触发后续的HTTP请求。有了Promise,我们可能会遇到竞争条件,因为我们无法控制我们收到回复的顺序,也无法取消旧的请求。 Rx解决了这个问题,允许我们在流之间切换,在我们不再关心的旧请求订阅上调用 Dispose 。我们也可能过滤掉任何无效的搜索输入,例如其中搜索字词的长度少于3个字符。

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

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

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

这些是一些快速示例,用于演示可能的内容。 Rx框架中有许多运算符可以满足所有类型的场景,Rx的可组合性意味着您可以轻松地组合运算符来定义所需的行为。创建自己的可重用运算符也很容易(例如RetryAfterDelay)。

总之,Rx可以做的事情比Promise可以做的更多,而且远远更多。我怀疑在接下来的几年里会继续转向Rx而不是Promises。

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

答案 3 :(得分:7)

Angular 2 guid

所述

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

但在某些情况下,请求始终只执行一次。您可以在服务器启动之前启动一个请求,取消它并发出不同的请求 回应了第一个请求。

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

  

请求 - 取消 - 新请求序列很难实现   承诺,但Observables很容易。

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

答案 4 :(得分:1)

通常将可观察量与承诺进行比较。以下是一些主要差异:

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

Observables提供了许多值。承诺提供一个。这使得observable可用于随时间获取多个值。

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

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

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

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

答案 5 :(得分:1)

可观察VS。诺言(Jeremy Vilken)

除新语法外, observables 是JavaScript应用程序的一种新模式,可用于 管理异步活动。它们也是以JavaScript语言本机实现的功能的草稿,因此该功能的重要性在于模式。 RxJS是 库,我们将使用它来帮助我们在应用程序中实现可观察性。

承诺是帮助处理异步调用的另一种结构,这很有用 例如,用于发出API请求。承诺的主要限制在于 仅在一个呼叫周期内有用。例如,如果您希望有一个承诺,请返回 诸如用户点击之类的事件的价值,则承诺将在首次点击时解决。但是您可能会对处理每个用户的点击操作感兴趣。通常,您会使用一个事件 侦听器,它使您可以随着时间处理事件。这是一个重要的区别:可观察对象就像事件处理程序一样,它们继续通过 时间并允许您持续处理该数据流。

答案 6 :(得分:0)

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

使一个复杂的概念变得神秘的最好方法是从头开始实施它。这是一个几乎纯粹的功能Observable实现和一个示例,不适用于Promise s:

/*** 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的计算是延迟的。另一方面,Promise会受到急切的评估,也就是说,它们一创建就开始运行。

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