谈谈ajax和fetch
ajax相关
- 客户端通过ajax向服务器发起这个请求
ajax优点:
- 局部刷新:ajax不用重新刷新整个页面,只是刷新局部页面,就可以与服务器交换数据
- 异步通信:ajax可以实现异步通信
ajax缺点:
- 会造成回调地狱
fetch相关
- fetch是基于promise的封装,是浏览器原生的api
- 原生fetch 本身并不提供请求超时、缓存、取消请求等能力,而在业务开发中却常常需要
- 没有办法做请求的进度处理,而ajax可以通过onprogress事件可以处理进度
如何取消请求
ajax取消请求
- 在使用 XMLHttpRequest 发送请求时,您可以使用
abort()方法来取消请求。
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.send();
// 在某些时候,您可以调用 xhr.abort() 来取消请求
xhr.abort();
fetch取消请求:
- 常用的方法是使用 AbortController 和 AbortSignal 对象来实现取消请求
- AbortController 是一个控制器对象,你可以通过 new 构造函数的形式返回一个 AbortSignal 对象
AbortSignal接口表示一个信号对象(signal object),它允许你通过AbortController对象与 Fetch 进行通信并在需要时将其中止请求AbortSignal 简单来说就是 用来传递中止信号
const controller = new AbortController();
const signal = controller.signal;
fetch(url, { signal }).then(response => {
// 处理响应
}).catch(error => {
// 处理错误
});
// 在某些时候,您可以调用 controller.abort() 来取消请求
controller.abort();
axios取消请求:
- Axios使用CancelToken
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.get(url, { cancelToken: source.token }).then(response => {
// 处理响应
}).catch(error => {
// 处理错误
});
// 在某些时候,您可以调用 source.cancel() 来取消请求
source.cancel();
如何超时处理
当前端向后端发起数据请求时,后端一直没有返回响应结果,不可能让用户一直等待下去,所以当请求超过一定的时间,就要提示用户或者取消这个请求
ajax超时处理
- XHR是支持超时处理的
- 通过timeout属性以及ontimeout事件
const xhr = new XMLHttpRequest()
// 超时设置 2s 设置(超过2s请求取消)
xhr.timeout = 2000
// 超时回调
xhr.ontimeout = function () {
alert('网络异常,请稍后重试!!!')
}
fetch超时处理
- fetch是不支持超时处理的
- 可通过AbortController 控制器来实现 配合 setTimeout
// 利用高阶函数封装 保证通用性、保持fetch功能不变
function createFetch(timeout) {
return (resource, options) => {
const controlller = new AbortController();
options = options || {};
options.signal = controlller.signal;
setTimeout(() => {
controlller.abort();
}, timeout);
return fetch(resource, options);
};
}
createFetch(2000)('url');
如何做请求超时重试?
什么场景需要超时重试? 一般情况下,不需要超时重试处理,请求重试一般是当网络异常,网络错误、断网的情况下,可以重试处理,在客户端比如小程序会用的比较多 超时时间一般是3-5秒的时间 请求重试需要考虑三个因素:
- 重试条件。比如网络错误,才会进行重试条件,
- 重试次数
- 重试延迟时间
axios超时重试处理
主要是当发生错误时,返回axios请求,就能重新请求
// 核心代码
return axios(config) // 能够进行请求失败重试
拦截器
axios.interceptors.response.use(null, (err) => {
let config = err.config;
if (!config || !config.retryTimes) return Promise.reject(err);
const { __retryCount = 0, retryDelay = 300, retryTimes } = config;
// 在请求对象上设置重试次数
config.__retryCount = __retryCount;
// 判断是否超过了重试次数
if (__retryCount >= retryTimes) {
return Promise.reject(err);
}
// 增加重试次数
config.__retryCount++;
// 延时处理
const delay = new Promise((resolve) => {
setTimeout(() => {
resolve();
}, retryDelay);
});
// 重新发起请求
return delay.then(function () {
return axios(config);
});
})。
适配器
1、适配器通过封装 XMLHttpRequest API 来发送 HTTP 请求
如何读取进度
ajax读取进度
- XHR是支持progress事件的, 通过progress事件拿到字节数、总字节数来实现
var xhr = new XMLHttpRequest()
xhr.open('POST', '/uploads')
xhr.onload = function() {}
xhr.onerror = function() {}
function updateProgress (event) {
if (event.lengthComputable) {
var percent = Math.round((event.loaded / event.total) * 100)
console.log(percent)
}
xhr.upload.onprogress =updateProgress; //上传的progress事件
xhr.onprogress = updateProgress; //下载的progress事件
}
xhr.send();
fetch读取进度
注意:fetch 方法无法跟踪 **上传 **进度,fetch是不支持progress事件,但是内部实现了Request和Response类, 可以跟踪 下载 进度
-
可通过Response实例访问 response.body
-
response.body是可读的字节流对象,可通过getRender()来读取响应
- 该字节流是可以循环读取的,直至body内容传输完成;
-
response.headers的
content-length获取总字节大小- 注意:如果使用gzip压缩,获取的文件大小会比实际文件大小要小
const RequestPercent = async ({
url = '',
option = {
headers: {
'Content-Type': 'application/pdf',
responseType: 'arraybuffer',
},
},
onprocess,
}) => {
const response = await fetch(url, option);
const reader = response?.body.getReader();
// 文件总长度
const contentLength = +response.headers.get('content-length');
let receivedLength = 0;
const chunks = [];
// eslint-disable-next-line no-constant-condition
while (true) {
const { done, value } = await reader.read();
if (done) {
break;
}
chunks.push(value);
receivedLength += value.length;
onprocess(receivedLength, contentLength);
}
return chunks;
};
如何携带Cookies
axios和fetch默认都不会携带cookies,需要配置,设置跨域请求时发送Cookie
fetch如何携带Cookies
fetch默认不会带cookie,需要添加配置项。
- 设置credentials属性为include
- omit: 默认值,忽略cookie的发送
- same-origin: 表示cookie只能同域发送,不能跨域发送
- include: cookie既可以同域发送,也可以跨域发送
axios如何携带Cookies
- 设置withCredentials属性设为 true