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”
因为应用了 TimeoutFetcherDecorator
,decoratedFetch('/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个计划及实现
- 更多文章...