fetch() 很好用,但还能更好用

fetch() API使你能够在 Web 利用中执行网络申请。

fetch() 的用法非常简单:通过调用 fetch('/movies.json') 启动申请,申请实现后失去一个 Response 对象,而后从中提取数据。

这是一个简略的例子,阐明如何从 /movies.json URL获取 JSON 格局的电影数据:

async function executeRequest() {  const response = await fetch('/movies.json');  const moviesJson = await response.json();  console.log(moviesJson);}executeRequest(); // logs [{ name: 'Heat' }, { name: 'Alien' }]

如下面的代码所示,你必须手动从响应中提取 JSON 对象:moviesJson = await response.json()。这样做一两次没什么问题。然而如果你的程序须要执行许多申请,那么重复用 await response.json() 提取 JSON 对象就显得有些蠢笨了。

这时就想到了应用第三方库,例如 axios,这个库大大简化了申请的解决。上面的代码用 axios 封装雷同的性能:

async function executeRequest() {  const moviesJson = await axios('/movies.json');  console.log(moviesJson);}executeRequest(); // logs [{ name: 'Heat' }, { name: 'Alien' }]

moviesJson = await axios('/movies.json') 可能返回理论的 JSON 响应,不用像 fetch() 那样手动提取JSON。

然而如果应用 axios 之类的库会带来一系列问题。

首先,它减少了 Web 程序的包大小;其次,你的程序与第三方库联合在了一起,不论是益处还是bug。

所以就想到了第三种办法——用装璜器模式来进步 fetch() API 的易用性和灵活性。

筹备Fetcher 接口

装璜器模式十分弱小,它可能以灵便和涣散耦合的形式在根本逻辑之上增加性能(也就是所谓的“装璜”)。

应用装璜器来加强 fetch() 须要几个简略的步骤。

第一步是申明一个名为 Fetcher 的形象接口:

type ResponseWithData = Response & { data?: any };interface Fetcher {  run(    input: RequestInfo,     init?: RequestInit  ): Promise<ResponseWithData>;} 

Fetcher 接口只有一个办法,该办法承受与一般 fetch() 雷同的参数并返回雷同类型的数据。

第二步是实现根本的访存器类:

class BasicFetcher implements Fetcher {  run(    input: RequestInfo,     init?: RequestInit  ): Promise<ResponseWithData> {    return fetch(input, init);  }}

BasicFetcher 实现 Fetcher 接口。它的run() 办法调用 fetch() 函数。就这么简略。

上面是用根本的 fetcher 类来获取数据的代码:

const fetcher = new BasicFetcher();const decoratedFetch = fetcher.run.bind(fetcher);async function executeRequest() {  const response = await decoratedFetch('/movies.json');  const moviesJson = await response.json();  console.log(moviesJson);}executeRequest(); // logs [{ name: 'Heat' }, { name: 'Alien' }]

const fetcher = new BasicFetcher() 创立 fetcher 类的实例。 decoratedFetch = fetcher.run.bind(fetcher) 创立了一个绑定办法。

而后,就能够用 decoratedFetch('/movies.json') 来获取 JSON 数据了,就像应用一般的 fetch() 一样。

在这个步骤中, BasicFetcher 类不会带来任何益处。而且因为引入了新的接口和类,使代码变得更加简单了。

JSON 提取装璜器

装璜器模式的外围是装璜器类。

装璜器类必须合乎 Fetcher 接口,包装装璜后的实例,并在 run() 办法中引入其余性能。

上面实现一个装璜器,它从 response 对象中提取 JSON 数据:

class JsonFetcherDecorator implements Fetcher {  private decoratee: Fetcher;  constructor (decoratee: Fetcher) {    this.decoratee = decoratee;  }  async run(    input: RequestInfo,     init?: RequestInit  ): Promise<ResponseWithData> {    const response = await this.decoratee.run(input, init);    const json = await response.json();    response.data = json;    return response;  }}

接下来看看 JsonFetcherDecorator 是怎么结构的。

JsonFetcherDecorator 合乎 Fetcher 接口。JsonExtractorFetch 中有公有字段 Decoratee,它也合乎 Fetcher 接口。在 run() 办法中,this.decoratee.run(input,ini) 获取数据。

而后 json = await response.json() 从响应中提取 JSON 数据。最初,response.data = json 将提取的 JSON 数据调配给响应对象。

上面用 JsonFetcherDecorator 装璜器来装璜 BasicFetcher,并简化 fetch() 的应用:

const fetcher = new JsonFetcherDecorator(  new BasicFetcher());const decoratedFetch = fetcher.run.bind(fetcher);async function executeRequest() {  const { data } = await decoratedFetch('/movies.json');  console.log(data);}executeRequest(); // logs [{ name: 'Heat' }, { name: 'Alien' }]

当初就能够间接从 response 对象的 data 属性拜访提取的数据,在每个应用 const { data } = decoratedFetch(URL) 的中央,都不用手动提取 JSON 对象了。

申请超时装璜器

默认状况下,fetch() API 的超时工夫受到浏览器的制约。在 Chrome 中,网络申请超时为 300 秒,而在 Firefox 中为 90 秒。

假如咱们最多能够期待 8 秒能力实现简略的申请,这时须要设置网络申请超时工夫,并在 8。秒后告诉用户无关网络问题的信息。

装璜器模式的长处在于:能够依据须要应用任意数量的装璜器来装璜根本实现。接下来再为 fetch 申请创立一个超时装璜器:

const TIMEOUT = 8000; // 8 秒超时class TimeoutFetcherDecorator implements Fetcher {  private decoratee: Fetcher;  constructor(decoratee: Fetcher) {    this.decoratee = decoratee;  }  async run(    input: RequestInfo,     init?: RequestInit  ): Promise<ResponseWithData> {    const controller = new AbortController();    const id = setTimeout(() => controller.abort(), TIMEOUT);    const response = await this.decoratee.run(input, {      ...init,      signal: controller.signal    });    clearTimeout(id);    return response;  }}

TimeoutFetcherDecorator 是实现 Fetcher 接口的装璜器。

如果申请没有在 8 秒内实现,那么在 TimeoutFetcherDecorator.run() 办法中的 controller.abort() 会停止申请。

测试一下:

const fetcher = new TimeoutFetcherDecorator(  new JsonFetcherDecorator(    new BasicFetcher()  ));const decoratedFetch = fetcher.run.bind(fetcher);async function executeRequest() {  try {    const { data } = await decoratedFetch('/movies.json');    console.log(data);  } catch (error) {    //如果申请超过8秒    console.log(error.name);  }}executeRequest(); //如果申请耗时超过8秒则输入 “AbortError”

因为应用了 TimeoutFetcherDecoratordecoratedFetch('/movies.json') 会引发超时谬误。

当初 fetch() 被 2 个装璜器包装:一个装璜器用于提取 JSON 对象,另一个在 8 秒内使申请超时。这就极大地简化了 DecoratedFetch() 的应用。

总结

fetch()API提供了申请的基本功能。然而只用 fetch() 会强制你从申请中手动提取 JSON 数据,本人去配置超时等等。

只管咱们能够应用第三方库,然而应用 axios 之类的库会减少程序包的大小,并减少耦合度。

通过应用装璜器模式,能够使装璜器从申请中提取 JSON,使申请超时等等。另外还能够随时合并、增加或删除装璜器,而不会影响应用了带装璜器的 fetch() 的其余代码。


本文首发微信公众号:前端先锋

欢送扫描二维码关注公众号,每天都给你推送陈腐的前端技术文章


欢送持续浏览本专栏其它高赞文章:

  • 深刻了解Shadow DOM v1
  • 一步步教你用 WebVR 实现虚拟现实游戏
  • 13个帮你进步开发效率的古代CSS框架
  • 疾速上手BootstrapVue
  • JavaScript引擎是如何工作的?从调用栈到Promise你须要晓得的所有
  • WebSocket实战:在 Node 和 React 之间进行实时通信
  • 对于 Git 的 20 个面试题
  • 深刻解析 Node.js 的 console.log
  • Node.js 到底是什么?
  • 30分钟用Node.js构建一个API服务器
  • Javascript的对象拷贝
  • 程序员30岁前月薪达不到30K,该何去何从
  • 14个最好的 JavaScript 数据可视化库
  • 8 个给前端的顶级 VS Code 扩大插件
  • Node.js 多线程齐全指南
  • 把HTML转成PDF的4个计划及实现

  • 更多文章...