即日起在codingBlog上分享您的技术经验即可获得积分,积分可兑换现金哦。

使用 Rx.JS 优化 Fetch API

微信 高效运维 25℃ 0评论
本文目录
[隐藏]

处理用户客户端(浏览器)与后端服务器的数据交互(一般通过 RESTful API)是前端开发最基本的问题之一。在浏览器里增删改查服务器端资源时,当前最普遍采用的解决方案是基于 Ajax 的回调或 Promise 。

1.

2.Fetch API 的问题


以 Fetch API 为例,想要获取一个位于http://api/v1/的资源foo(id = 123),可以生成资源 URI 如http://api/v1/foo/123,将所需的参数构造好,最后发送 HTTP 请求fetch(‘http://api/v1/foo/123’),结果作为 Promise返回。

对于业务单一的简单Web应用例如新闻 Feed网站,这样的调用模式足够了。但对于高响应式的复杂Web应用例如 SaaS 控制台,可能存在两个很重要的需求:

  • 缓存。对获取过的数据,可以先返回缓存的数据,而不去调用 API

  • 数据更新通知。如果客户端或是服务器端更新了数据,需要通知到资源使用者

2.1.

2.2.基于资源特征(URI)的缓存机制


缓存的一种解决方案是,将 Fetch API 简单封装,使得在 HTTP API 调用层可以针对每次请求的特征(比如URI、请求参数、请求方法等)进行缓存。这种方式初看思路简单,对现有系统的侵入性也不大,但实际使用上问题较多。

上述缓存方式的问题在于,客户端代码对服务器资源的调用方法过于透明,缺少资源的抽象,导致增删改操作的副作用不好控制,往往使得处理缓存的逻辑变得很复杂。举个例子,资源 foo(id=123) 可能存在于多个 RESTful 路径上,比如/foo (foo资源的列表) 和/foo/123。缓存该资源查询后,针对 foo(id=123) 的每次更新操作都需要枚举所有 URI 进行 Cache busting。

有的同学可能就说了,是不是可以在获取某个资源的时候,有缓存就立刻返回缓存的数据,同时重新调用一次 API,当数据更新时再返回新数据。这种思路在我看来是种解决方案,但HTTP返回值是个 Promise,实现起来会十分别扭。Promise 实际上是对于未来某个可能发生结果(也就是回调函数)的抽象,且结果的返回是一次性的,就导致它灵活性不足。

3.使用 RxJS 封装 Fetch API

下面是经过 Rxjs 封装过的 Fetch request:

使用上,针对某种特定的资源 URI 必须要有一个单例FetchDataStore来封装它的 Fetch 过程。

举一个例子,对于应用内的资源foo(id=123),我们可以这样封装它:

跟 Promise 版本相比,封装后的 Fetch datastore 有几个好处:

  • 惰性加载的缓存

    –  对 Rx 有研究的朋友应该能看出,data$在第一次被订阅时,有从cold 转为 hot Observable切换的一段时间。

  • 可以被动的响应更新事件

  • 还可以通过 RxJS operators 进行进一步变化数据流

    –  比如和 WebSocket 进行结合,实现服务器端推送

不过,上面的解决方案还是需要用户在合适的时机调用refetch函数,保证多个观察者的数据能一直处在最新状态。

3.1.

3.1.

3.3.更进一步


作者粗略的扫了一下 teamabition 的基于 Rxjs 的数据同构 SDK 。跟上面简单的 Fetch API 相比,teambition SDK 需要使用者引入下面两个规则:

Model Schema: 任意资源需要有自己独立的标示方式,并且保证在不同的上下文中保持 Schema 一致。使用 Schema 通常意味着需要引入一种类型系统,目前最常见的是 TypeScript 。

资源的数据交互都是通过封装的 Model 接口进行,避免直接调用 API。

加上数据模型抽象后,就可以在大多数情况下避免主动调用API,简化 View 层逻辑。

另外要时刻谨记:系统越复杂,出问题的可能性越大。保持系统简单高效是最好的。

本文作者:灵雀云-肖鹏

灵雀云 释放云的无限潜能
长按,识别二维码,加关注


点击“阅读原文”,了解灵雀云

转载请注明:CodingBlog » 使用 Rx.JS 优化 Fetch API

喜欢 (0)or分享 (0)
发表我的评论
取消评论

*

表情