原文载于我的博客 http://www.tangshuang.net/381...

这里主要探讨一下怎么把数据请求从业务代码中抽象出来。

传统的数据请求方式是我们在具体的业务代码,或某些特定的逻辑代码(例如redux的action)中手工写一个ajax,无论是使用最新的fetch api,还是使用axios,都是在直接构建一个请求发送器和控制请求过程。当然,这是比较容易理解的,任何人单独看这段代码都能读懂。

但是在很多项目中,请求往往都越来越固定,总的和backend打交道的api估计不超过20个,所以我们尝试把所有的请求封装在一个services文件夹里面,形成一个独立的module,请求某个数据的时候,我们调用这个module的某个api。这种操作比前面的方式显然上升了一个层面。

但是,我们会遇到问题。当应用中的两段代码,同时使用了一个service,如果不加处理,就会导致同一个页面,同一时间,对一个backend api发出两个相同的请求。这种情况在我之前的项目中经常出现:一个页面里面有两个组件的实例。之前想到了使用cache,当一个请求发出的时候,发现参数都没变,那么直接把cache的数据返回好了,这样还可以提高数据请求的性能。然而,这完全没有解决掉问题,因为当第一次数据请求的时候,cache是没有的,两个请求还是会同时发出。后来想到,把这请求的promise缓存起来,当第一个请求发出之后,第二个请求准备发之前,先去检查cache列表中存不存在同请求的promise,如果存在,直接返回这个promise,这样,当这个promise成功的时候,两个地方的then都被触发了。

接下来,我们发现还有另外一种需求,当一个页面里面同一个组件渲染了两个实例的时候,一个实例请求到新数据,我们还希望另一个实例也可以得到这个数据,至于是否刷新界面,可以由程序来决定。这是非常好的准备使用观察者模式的场景。

观察者模式,简单的说,就是“订阅-分发”模式,观察者(订阅者)subscribe一个或多个特定订阅,当被订阅的内容发生变化时,发布者便把这些变化分发给订阅者。之所以叫观察者,是因为当观察者本身并不做任何和订阅内容相关的工作,只处于一个干自己的事,但是时时刻刻盯着自己订阅的内容,一旦收到订阅通知时,马上干对应的事。

上面的场景就是这样一种场景。我们需要独立出一个观察者,这就是datamanager,它接受来自页面内两个实例的订阅,当其中一个订阅者通过datamanager的api触发了数据请求,导致两个实例订阅的相同内容发生改变时,datamanager将新的内容同时分发给这两个实例。

看上去非常简单的逻辑,实现起来却不那么简单。索性你可以通过这里直接阅读源码来了解我是怎么实现的。

使用datamanager也很简单:

npm install --save datamanager.js

然后在你的代码中使用它:

import DataManager from 'datamanager.js'

const datamanager = new DataManager()
datamananger.register([ ...datasources ]) // datasource请阅读文档

datamanager.subscribe('datasourceId', (data) => {
  // 这里可以执行ComponentB的重新渲染动作
})

在另外的代码中可以通过request来获取数据:

// ComponentA里面执行
async () => {
  let data = await datamanager.request('datasourceId') // 当数据回来时,上面的subscribe里的回调函数会被执行
  // 用data做点事
}

datamanager提供来subscribe来进行订阅,只需要在subscribe的第二个参数中告诉datamanager,对应的datasourceId数据回来之后,自己要做什么就可以了。

回头再来看datamanager,你就发现,它不需要你告诉单次请求的url,而是把url通过datasource注册进去,它的本意就是,这个datasource可能会反复使用,因此你只需要记住它的id即可。这和我们传统的request就开始有些不同了。

request方法是完全按照传统请求返回promise的思想设计的,真正的datamanager的思想精髓,是在于它提供的get方法,当你熟悉datamanager的操作之后,开始使用get方法,而完全忘掉request方法的时候,你会发现,datamanager中完全没有数据请求的概念。它提供了一种新的思路:对于一个应用,和backend api打交道的部分被抽象出来,应用只从datamanager获取数据,而不关心它是怎么从backend拿到数据的

对于应用而言,datamanager就在那里,你通过register注册datasource之后,就只管找它要数据就是了,要数据,给数据,要数据,给数据。后端?我不管你怎么从后端拿数据,反正我只知道数据应该在你那里。它就像一个data center,管理着前端数据。但同时,它又是observer,为实现数据在不同实例间的实时共享提供了便利。

这里可以透露一下,datamanager内部是用axios请求数据,但是对于开发者而言,不需要知道(还是需要知道axios的response结构的,如果有需要的话)。当然,这里需要说明的是,backend还是在的,只是你把backend的信息放到了datasource中,一次性注册进了datamanager。

总而言之,datamanager是对前端数据请求的一次提炼,这种提炼把前端负责的分散的数据请求代码规整化,把datasource集中管理,在代码中,不考虑请求这个动作,而是从datamanager中直接拿一个数据,拿到的是什么就是什么,不需要质疑。注意“直接”这个词,“不考虑请求”的意思是说“未来的前端没有代码层面的ajax”,只需要拿数据,只需要拿数据。


否子戈
2.2k 声望143 粉丝

疯狂前端开发中……