原生的 html5 API fetch 并不支持 timeout 属性, 习惯了 jQuery 的 ajax 配置的同学, 如果一时在 fetch 找不到配置 timeout 的地方, 也许会很纠结. fetch 的配置 API 如下:
语法
fetch(input, init).then(function(response) { ... });
参数
input
定义要获取的资源. 这可能是: 一个 USVString 字符串, 包含要获取资源的 URL. 一个 Request 对象.
init 可选 一个配置项对象, 包括所有对请求的设置. 可选的参数有:
method: 请求使用的方法, 如 GET,POST.
headers: 请求的头信息, 形式为 Headers 对象或 ByteString. body: 请求的 body 信息: 可能是一个 Blob,BufferSource,FormData,URLSearchParams 或者 USVString 对象. 注意 GET 或 HEAD 方法的请求不能包含 body 信息.
mode: 请求的模式, 如 cors, no-cors 或者 same-origin.
credentials: 请求的 credentials, 如 omit,same-origin 或者 include.
cache: 请求的 cache 模式: default, no-store, reload, no-cache, force-cache, or only-if-cached.
根本找不到 timeout 配置, 本文和大家分享如何快速实现 fetch 的 timeout 功能.
我们先实现 abort 功能, 但由于初始化 fetch 后, 返回的是一个 Promise 对象, 那么需要在 abort 后达到触发 rejectPromise 的效果.
如果要沿用 fetch 返回的 Promise 来实现 abort 估计是达不到效果的, 这里需要借助自己的一个 Promise 实例来达到目的.
- var abort_fn = null;
- var abort_promise = new Promise(function(resolve, reject) {
- abort_fn = function() {
- reject('abort promise');
- };
- });
这个简单的代码段, 可以通过调用 abort_fn 函数就可以触发 abort_promise 的 reject.
fetch 返回的 promise 我们暂且称为 fetch_promise 吧, 那么现在有两个 promise:abort_promise 和 fetch_promise.
每个 promise 都可以绑定 resolve callback 和 reject callbck, 那么后续 then 的回调绑定到哪个 promise 上呢, 这是一个问题.
这里我们使用 Promise 非常好用的 Promise.race 方法, 他可以帮我们解决这个问题:
Promise.race 概述
Promise.race(iterable) 方法返回一个 promise, 这个 promise 在 iterable 中的任意一个 promise 被解决或拒绝后, 立刻以相同的解决值被解决或以相同的拒绝原因被拒绝.
合体:
- function abortablePromise(fetch_promise) {
- var abort_fn = null;
- // 这是一个可以被 reject 的 promise
- var abort_promise = new Promise(function(resolve, reject) {
- abort_fn = function() {
- reject('abort promise');
- };
- });
- // 这里使用 Promise.race, 以最快 resolve 或 reject 的结果来传入后续绑定的回调
- var abortable_promise = Promise.race([
- fetch_promise,
- abort_promise
- ]);
- abortable_promise.abort = abort_fn;
- return abortable_promise;
- }
经过 abortablePromise 包裹后的 promise 都会返回一个新的 promise, 不同的是带上了一个 abort 方法. 使用例子:
- var p = abortablePromise(fetch('//a.com/b/c'));
- p.then(function(res) {
- console.log(res)
- }, function(err) {
- console.log(err);
- });
- // 假设 fetch 要 3 秒, 但是你想在 2 秒就放弃了:
- setTimeout(function() {
- p.abort(); // -> will print "abort promise"
- }, 2000);
目前为止, 大体功能已经实现, 再稍微调整, 让调用更方便:
- function _fetch(fetch_promise, timeout) {
- var abort_fn = null;
- // 这是一个可以被 reject 的 promise
- var abort_promise = new Promise(function(resolve, reject) {
- abort_fn = function() {
- reject('abort promise');
- };
- });
- // 这里使用 Promise.race, 以最快 resolve 或 reject 的结果来传入后续绑定的回调
- var abortable_promise = Promise.race([
- fetch_promise,
- abort_promise
- ]);
- setTimeout(function() {
- abort_fn();
- }, timeout);
- return abortable_promise;
- }
- //usage:
- _fetch(fetch('//a.com/b/c'), 2000)
- .then(function(res) {
- console.log(res)
- }, function(err) {
- console.log(err);
- });
全文完
来源: https://juejin.im/entry/5afaadc46fb9a07a9c045e76