取消请求 在某些项目中还是有必要的
目前我能想到的关于fetch的取消请求的方法有两种:
cancelIdleCallback:兼容性差得很Promise.race,将abrot_promise函数(reject)挂在请求实例上,然后手动调用abrot即reject看看方法2的具体实现:(我目前能想到但不优雅的方法)
/**
* fetch 封装,timeout,cancel;
========================
const p = $get(
"https://api.apiopen.top/getJoke",
{
page: 1,
count: 2,
type: "video"
},
{
credentials: "omit",
headers: {
"Content-Type": "text/plain"
}
}
);
console.log(p);
p.then(res => {
console.log("res:::", res);
}).catch(err => {
console.log("err:::", err);
});
// 手动取消请求
p.cancel();
*/
import { qsStringify } from "./util";
// 默认超时:30s
const defaultTimeout = 30 * 1000;
// 默认url
const defaultURL = "";
// 默认fetch配置
const defaultConfig = {
credentials: "include",
mode: "cors",
cache: "default",
headers: {
"Content-Type": "application/json"
}
};
// 校验status状态码
const checkStatus = (reject, response) => {
const response2json = response.json();
if (response.status >= 200 && response.status < 300) {
console.log("response2json: ", response2json);
return response2json;
} else {
reject(response2json);
}
};
export const _fetch = (fetch => (
url,
{ timeout = defaultTimeout, ...rest }
) => {
console.log(url, { timeout, ...rest });
// 定义终止函数
let Abort = null;
// 可被终止(reject)的promise
const abort_promise = new Promise((resolve, reject) => {
Abort = (msg = "canceled.") => {
reject(msg);
};
});
// 调用超时
if (timeout && typeof abort === "function") {
setTimeout(() => {
Abort(`timeout:${timeout}ms`);
}, timeout);
}
// 业务API的promise
const fetch_promise = new Promise((resolve, reject) => {
if (!url.startsWith("http")) {
url = `${defaultURL}${url}`;
}
fetch(url, rest)
.then(response => checkStatus(reject, response))
.then(data => {
// 这里setTimeout用于测试
setTimeout(() => {
resolve(data);
}, 5 * 1000);
// resolve(data);
})
.catch(error => {
console.log("request fail url:", url);
console.log("request fail reason:", error);
reject(error);
});
});
// race:返回最快的结果(resolve/reject)
const promise = Promise.race([fetch_promise, abort_promise]);
// console.log(promise)
// 将终止函数作为结果返回,达到可取手动取消请求的目的
promise.cancel = Abort;
return promise;
})(fetch);
export const generateConfig = (method, params, config) => {
const finalConfig = { ...defaultConfig };
if (method === "GET") {
Object.assign(finalConfig, { method }, config);
} else if (method === "POST" || method === "PUT" || method === "DELETE") {
const body = JSON.stringify(params);
Object.assign(finalConfig, { method }, { body }, config);
} else if (method === "UPLOAD") {
const formData = new FormData();
if (!params.length) {
return { success: false, message: "未选择文件" };
}
for (const i of params) {
const path = i.path;
const arr = path.split("/");
const file = {
uri: path,
type: "multipart/form-data",
name: escape(arr[arr.length - 1]),
fileType: i.mime
};
formData.append("file", file);
}
Object.assign(
finalConfig,
{ method: "POST" },
{ headers: { "Content-Type": "multipart/form-data" } },
{ body: formData },
config
);
}
return finalConfig;
};
export const $get = (url, params = {}, config = {}) => {
url = `${url}?${qsStringify(params)}`;
const finalConfig = generateConfig("GET", params, config);
return _fetch(url, finalConfig);
};
export const $post = (url, params = {}, config = {}) => {
const finalConfig = generateConfig("POST", params, config);
return _fetch(url, finalConfig);
};
export const $put = (url, params = {}, config = {}) => {
const finalConfig = generateConfig("PUT", params, config);
return _fetch(url, finalConfig);
};
export const $delete = (url, params = {}, config = {}) => {
const finalConfig = generateConfig("DELETE", params, config);
return _fetch(url, finalConfig);
};
export const $upload = (url, fileArr = [], config = {}) => {
const finalConfig = generateConfig("UPLOAD", fileArr, config);
return _fetch(url, finalConfig);
};
在线测试&查看代码:codesandbox
我简单看了一下umi-request源码,我这种方法,不太好加入进去(功力不够,提pr心有余力不足),希望大佬们能增加取消请求的功能🙏。
取消请求的能力目前正在 beta 测试中,刚好是你提 issue 的前一天,欢迎提前尝鲜:https://www.npmjs.com/package/umi-request/v/1.2.3-beta.1
取消请求的能力目前正在 beta 测试中,刚好是你提 issue 的前一天,欢迎提前尝鲜:https://www.npmjs.com/package/umi-request/v/1.2.3-beta.1
看了一下和axios,用的是一样的
@chenjsh36 Timeout 异常抛出后 http request 根本没有cancel 还是发送并且成功了
fetch 返回 promise,但是 js 并没有 “中止” promise 的概念
fetch本身没有abrot方法,即使有一个AbortController兼容太差,
不像axios,web端用的XML,node端用的http的request,他们都有abrot方法
Most helpful comment
取消请求的能力目前正在 beta 测试中,刚好是你提 issue 的前一天,欢迎提前尝鲜:https://www.npmjs.com/package/umi-request/v/1.2.3-beta.1