【问题标题】:Angular - RxJS operator .first() throws type error after upgrade from Http to HttpClientAngular - 从 Http 升级到 HttpClient 后,RxJS 运算符 .first() 抛出类型错误
【发布时间】:2018-02-01 09:40:21
【问题描述】:

我最近升级了我的 Angular 应用程序以使用 HttpClient 而不是 Http。在对标头和参数的处理进行了一些修复之后,我的大部分代码都能正常工作,但是一个特定的请求暗示我这是一种奇怪的行为。

该请求有点特殊,因为它是一个轮询请求,当它从服务器获取有效负载时会退出(它会返回 204 响应,直到它有东西要交付)。

我使用间隔 Observable 在特定的时间跨度内每秒轮询一次端点,当我获得有效负载时,我使用 .first() 运算符来处理数据。当我使用旧的 Http 服务时,这工作得很好。下面是它的外观:

return Observable.interval(this.pollInterval)
  .mergeMap(() => this.http.get(this.apiUrl + '/poll'))
  .first(data => data) // This is where the error occurs in HttpClient
  .map(result => result)
  .timeout(20000)
  .catch(this.errorHandler);

当我使用已弃用的 Http 服务时,observable 可以正常工作,但是当我使用 HttpClient 服务时,我收到以下错误:

error TS2345: Argument of type '(data: Object) => Object' is not assignable to parameter of type '(value: Object, index: number, source: Observable<Object>) => boolean'. Type 'Object' is not assignable to type 'boolean'.

现在这里有点奇怪,我决定尝试通过在 .first() 运算符之前添加一个 .do(console.log) 来调试可观察流,如下所示:

return Observable.interval(this.pollInterval)
  .mergeMap(() => this.http.get(this.apiUrl + '/poll'))
  .do(console.log)
  .first(data => data)
  .map(result => result)
  .timeout(20000)
  .catch(this.errorHandler);

这样做似乎解决了问题,不再出现类型分配错误,并且所需的功能像以前一样工作。我已经使用了我在 .do() 运算符中调用的虚拟函数,但我不满意必须这样做来解决问题,所以我想弄清楚为什么会出现这种行为以及是什么.do() 运算符确实可以解决问题。

期待听到您对此问题的意见。

解决方案 我遵循了第一个答案的建议并使用了!在 .first() 返回中将数据类型转换为布尔值,这消除了类型错误并消除了使用问题中描述的 .do() 操作的需要。

【问题讨论】:

  • 您不必在 GET 请求上使用 first()

标签: angular rxjs rxjs5 angular-httpclient


【解决方案1】:

如果do() 解决了这个问题,它实际上看起来像是do() RxJS https://github.com/ReactiveX/RxJS/commit/9a40297 的问题。

无论如何,first() 的回调需要以下类型 (http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-first):

function(value: T, index: number, source: Observable<T>): boolean

我认为该错误可以告诉您确切的问题所在。您正在使用first(data =&gt; data),因此您不会返回boolean,而是返回Object

如果我了解您想要做什么,您需要根据对象是否存在将其转换为 truefalse

.first(data => !!data)

...或者也许不是蹩脚的解决方案:

.first(Boolean)

另一个问题是你是否甚至需要使用first。如果源 Observable 完成并且没有匹配的项目或者它完成并且有多个匹配项目并且我认为这些chan在您的情况下都不会发生,这意味着会发出错误。所以也许使用filter(Boolean) 会更有意义。

【讨论】:

  • 这肯定解决了问题,我将研究过滤器变体,以类似的方式使用过滤器进行了快速测试,但这并没有像何时停止订阅外部 observable我使用 .first,但可能是我实施错了,如果可以的话,我会投票,仍然需要 4 分才能做到这一点,所以我稍后会回来!很好的答案!谢谢!
  • 我不知道你的用例是什么,但听起来你可能想使用 takeWhile() 而不是 filter()first 如果你想在什么时候完成链满足一个条件。 reactivex.io/rxjs/class/es6/…
  • 我轮询的 api 端点返回 null 直到它有我需要的数据,所以我将继续轮询端点直到我得到一个非空值,一直在查看 rx 文档,并且first 似乎最适合这里,takeWhile() 将在我获得数据后立即放弃订阅,如果我正确理解它,它不会传播我想要的数据( takeWhile(response => response == null ))。现在看来 .first() 将按照我想要的方式执行流:)
猜你喜欢
  • 2020-10-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-11
  • 1970-01-01
  • 2014-07-02
相关资源
最近更新 更多