【问题标题】:http request within Observable happens even without subscription即使没有订阅,Observable 中的 http 请求也会发生
【发布时间】:2018-11-13 17:31:22
【问题描述】:

我看到 http 请求发生了 - 在 Chrome 网络选项卡中,也通过在 fetch 承诺中使用 then() - 使用以下代码,尽管从未订阅过内部可观察 (saveCourses$)。

根据更新的 rxjs 文档,我修改为使用 from() 而不是 fromPromise(),但同样的情况发生了。

我的理解是内部的 Observable 不应该运行?

ngOnInit() {
  this.form.valueChanges.pipe(
    filter(() => this.form.valid)
  )
    .subscribe(changes => {
      const saveCourses$ = fromPromise(fetch(`/api/courses/${this.course.id}`, {
        method: 'PUT',
        body: JSON.stringify(changes),
        headers: {
          'content-type': 'application/json'
        }
      }));
    });
}

【问题讨论】:

  • fromPromise 方法很可能会立即使用 Promise 以将其转换为可观察对象。你为什么不使用内置的 Angular http 东西来按你想要的方式做事?
  • 我正在学习关于 rxjs 的 Angular 大学课程 - 我不打算在任何项目中使用 fetch,但对于这个示例,我理解 http 请求不应该在没有订阅的情况下发生(根据致尚未回复我的课程作者)。我真的很想知道为什么会发生这种自动订阅
  • 如前所述,它发生在fromPromise 代码中。代码中传递给Observable 的回调是立即调用then 方法。 github.com/ReactiveX/rxjs/blob/…

标签: javascript angular ecmascript-6 rxjs6


【解决方案1】:

虽然基于 Observable 的接口通常会将昂贵的工作(如网络调用)推迟到它们被订阅,但这并不是绝对必要的。有时,一个返回 Observable 的方法甚至在其 subscribe 方法被调用之前就已经完成或开始了很多工作。如果 Observable 在订阅之前确实可以工作,那么它通常被称为“热”(与“冷”的 Observable 相对,除非附加订阅者,否则它不会工作)。请参阅此处的"Hot and Cold Observables" 部分。

Promise-based 接口的工作方式很像“热”的 Observables。也就是说,我们希望一旦我们调用给我们 Promise 的函数,就会启动潜在的昂贵操作。当 Promise 被解析时,我们会了解操作的结果,但无论我们是否真正监听它,它都会解析(即,将“then”处理程序连接到 Promise)。

在您的示例中,您的 Observable 是使用fromPromise 方法创建的

fromPromise(fetch(`/api/courses/${this.course.id}`...)

fromPromise 的工作原理本质上是等待 Promise 被解析,当它被解析时,通过新创建的 Observable 发出 Promise 的解析值。这里重要的是fromPromise 必须调用 fetch() 才能获得构建 Observable 的 Promise。并且调用 fetch 的行为会导致网络调用被发起。

因此,在这种情况下,与大多数将 Observables 用于网络或其他长操作的“典型”用途不同,您无需调用 .subscribe() 来执行操作。它会在调用fetch 时立即执行,而fetch 在 Observable 被创建 时调用,而不是在订阅 时调用。

【讨论】:

  • 感谢您清晰详细的解释。还有一点——我创建了一个在 Observable.create() 方法中调用 fetch 的函数,在这种情况下,除非我明确订阅,否则不会触发 http 请求——所以这意味着它特别是 fromPromise 和 fetch 的组合导致原始问题中的问题,而不仅仅是使用 fetch,是否正确?
  • @DJC 对,不同的是你传递给Observable.create的函数只有在Observable被订阅时才会被调用。将此与 fromPromise 的行为进行对比,当 Observable 被 创建 时调用提供的函数。 reactivex.io/documentation/operators/create.html
  • 完美 - 非常感谢您的详细解释。原来 Angular 大学弄错了;)
【解决方案2】:

停止使用fetch 并使用HttpClient。如果您打开控制台并输入fetch('foo'),您将看到一个网络请求。问题在于 fromPromise 之前的调用。

【讨论】:

  • 我正在学习关于 rxjs 的 Angular 大学课程 - 我不打算在任何项目中使用 fetch,但对于这个示例,我理解 http 请求不应该在没有订阅的情况下发生(根据致尚未回复我的课程作者)。我真的很想了解为什么会发生这种自动订阅
猜你喜欢
  • 2019-07-14
  • 2018-12-21
  • 2019-12-30
  • 2019-07-18
  • 2011-02-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-23
相关资源
最近更新 更多