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 个计划及实现
- 更多文章 …