跳到主要内容

谈谈ajax和fetch

ajax相关​

  • 客户端通过ajax向服务器发起这个请求

ajax优点:

  • 局部刷新:ajax不用重新刷新整个页面,只是刷新局部页面,就可以与服务器交换数据
  • 异步通信:ajax可以实现异步通信

ajax缺点:

  • 会造成回调地狱

fetch相关​

  • fetch是基于promise的封装,是浏览器原生的api
  • 原生fetch 本身并不提供请求超时、缓存、取消请求等能力,而在业务开发中却常常需要
  • 没有办法做请求的进度处理,而ajax可以通过onprogress事件可以处理进度

如何取消请求​

ajax取消请求​

  • 在使用 XMLHttpRequest 发送请求时,您可以使用 abort() 方法来取消请求。
js
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 简单来说就是 用来传递中止信号

js
const controller = new AbortController();
const signal = controller.signal;

fetch(url, { signal }).then(response => {
// 处理响应
}).catch(error => {
// 处理错误
});

// 在某些时候,您可以调用 controller.abort() 来取消请求
controller.abort();

axios取消请求:​

  • Axios使用CancelToken
js
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事件
js
const xhr = new XMLHttpRequest()
// 超时设置 2s 设置(超过2s请求取消)
xhr.timeout = 2000
// 超时回调
xhr.ontimeout = function () {
alert('网络异常,请稍后重试!!!')
}

fetch超时处理​

  • fetch是不支持超时处理的
  • 可通过AbortController 控制器来实现 配合 setTimeout
js
// 利用高阶函数封装 保证通用性、保持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请求,就能重新请求

js
// 核心代码
return axios(config) // 能够进行请求失败重试

拦截器​

js
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事件拿到字节数、总字节数来实现
javascript
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压缩,获取的文件大小会比实际文件大小要小
javascript
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