前端取消接口调用的方法示例

 更新时间:2025年03月04日 09:29:56   投稿:daisy  
这篇文章主要介绍了前端取消接口调用的相关资料,讲解了XMLHttpRequest和AbortController两种取消HTTP请求的方法,XMLHttpRequest通过abort()方法取消请求,而AbortController提供了一个更现代和灵活的解决方案,需要的朋友可以参考下

1. xmlHttpRequest是如何取消请求的?

实例化的XMLHttpRequest对象上也有abort方法

const xhr = new XMLHttpRequest();
xhr.addEventListener('load', function(e) {
  console.log(this.responseText);
});
xhr.open('GET', 'https://jsonplaceholder.typicode.com/todos/1');
xhr.send();

// 返回
{
  "userId": 1,
  "id": 1,
  "title": "delectus aut autem",
  "completed": false
}

如果在send后直接abort取消

// xhr的取消操作:执行过程比较模糊,不知道abort什么时机进行处理
xhr.abort()

如果在定时器中(当定时器的时长那个和接口请求时长差不多)取消请求,会发现资源已经获取到了,但是控制台没有打印

2. AbortController

const ac = new AbortController();
const { signal } = ac;
const url = "https://jsonplaceholder.typicode.com/todos/1";
​
fetch(url, { signal })
  .then((res) => res.json())
  .then((json) => console.log(json));

直接使用abort取消请求

ac.abort()

这里报错的原因是没有对错误进行捕获

// 修改后的代码
fetch(url, { signal: ac.signal })
  .then((res) => res.json())
  .then((json) => console.log(json))
  .catch(e => console.log(e)) // DOMException: signal is aborted without reason
ac.abort() // abort接受一个入参,会被传递到signal的reason属性中

为什么可以这样取消?

fetch监听signal对象的状态,进而可以终止请求

2.1 如何同时取消多个请求?

const ac = new AbortController();
const { signal } = ac;
const url = "https://jsonplaceholder.typicode.com/todos";
​
const todoRequest = (id, { signal }) => {
  fetch(`${url}/${id}`, { signal })
    .then((res) => res.json())
    .then((json) => console.log(json))
    .catch((e) => console.log(e)); // DOMException: signal is aborted without reason
};
​
todoRequest(1, { signal });
todoRequest(2, { signal });
todoRequest(3, { signal });
​
ac.abort("cancled");

2.2 AbortSignal

是一个接口,用于表示一个信号对象,它允许你与正在执行的异步操作通信,以便可以在操作完成之前将其中止。

2.3 AbortSignal的方法

2.3.1 abort

静态方法,用于创建一个已经中止的 AbortSignal 对象。当你调用这个方法时,它会返回一个带有 aborted 状态为 true 的 AbortSignal 实例。

const signalAbout = AbortSignal.abort(); // AbortSignal {aborted: true, reason: DOMException: signal is aborted without reason...}

2.3.2 throwIfAborted 方法

用于在执行代码之前检查 AbortSignal 是否已经被中止。如果 AbortSignal 已经被中止,它会抛出一个 AbortError。这个方法可以帮助开发者在执行特定操作之前确保没有被中止,以避免不必要的处理。

const signalAbout = AbortSignal.abort('abortedReason');
try {
    signalAbout.throwIfAborted(); // 抛出error: abortedReason
} catch (error) {
    console.log(error);
}

2.3.3 timeout

用于创建一个在指定时间后自动中止的 AbortSignal 对象。这在需要设置请求超时时非常有用。

// 使用 AbortSignal.timeout 设置 10ms超时
const signalAbout = AbortSignal.timeout(10);
const todoRequest = (id, { signal }) => {
  fetch(`${url}/${id}`, { signal })
    .then((res) => res.json())
    .then((json) => console.log("json: ", json))
    .catch((e) => console.log("err: ", e)); //DOMException: signal timed out 
};
todoRequest(1, { signal: signalAbout });

2.3.3.1 添加事件监听 => 从没有终止到被终止

AbortSignal继承自EventTarget,因为 AbortSignal 是用来监听 abort 事件的,而 EventTarget 提供了添加、移除和触发事件监听器的机制。

const signalAbout = AbortSignal.timeout(10);
signalAbout.addEventListener("abort", (e) => {
    console.log("aborted: ", e);
})​

e的打印如下:

3. 实现一个主动取消的promise

const ac = new AbortController();
const { signal } = ac;
​
const cancelablePromise = ({signal}) => 
    new Promise((resolve, reject) => {
        // 情况1:直接主动取消
        signal?.throwIfAborted(); // 也可以用reject
​
        // 情况2:正常处理业务逻辑
​
        setTimeout(() => {
            Math.random() > 0.5 ? resolve('data') : reject('fetch error');
        }, 1000);
​
        // 情况3:超时 todo?
​
        // 监听取消
        signal.addEventListener("abort", () => {
            reject(signal?.reason);
        });
    })
// 发起网络请求
cancelablePromise({signal})
.then(res => console.log('res: ', res))
.catch(err => console.log('err: ', err))
// 情况1 
// ac.abort('用户离开页面了') // err:  用户离开页面了
​
// 情况2 正常请求 err:  fetch error || res:  data

4. 如何使用signal取消事件监听?

当对一个元素添加了多个事件监听,不需要像removeEventListener一样,每个事件都需要取消一次,每次都要写明对应事件的事件句柄

使用signal 只需要取消一次信号,全部事件监听都被取消

const ac = new AbortController();
const { signal } = ac;
const eleA = document.querySelector('#a');
const eleB = document.querySelector('#b');
​
function aEleHandler () {}; // 事件
eleA.addEventListener('click', aEleHandler, {signal}); // 无论绑定多少个事件,都只需要一个signal
​
eleB.addEventListener('click', () => {
    ac.abort(); // 只需要取消一次
})

5. 请求多个接口进行数据组装的场景

当网速不好的时候,如何取消这种不断进行的网络请求?

const ac = new AbortController();
const { signal } = ac;
const fetchAndRenderAction = (signal) => {
    requestData(signal); // 多个串行或者并行的接口
    drawAndRender(signal); // 异步渲染
}
​
try{
    fetchAndRenderAction({signal})
}catch{
    // dosomething...
}

6. 总结

对于用户主动离开页面,或者用户的网络很卡的时候(预期返回顺序是:接口1 => 接口2;但是接口1返回太慢,导致顺序混乱。)这就需要手动终止请求。构造函数AbortController的实例信号量signal(可以作为ref存储起来),signal作为fetch的参数,在每次请求的时候,可以手动调用abort方法,取消上一次的请求。

到此这篇关于前端取消接口调用的文章就介绍到这了,更多相关前端取消接口调用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • JavaScript计算出两个数的差值

    JavaScript计算出两个数的差值

    这篇文章主要为大家详细介绍了JavaScript计算出两个数的差值,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-03-03
  • 浅谈JS函数节流防抖

    浅谈JS函数节流防抖

    本篇文章主要介绍了JS函数节流防抖,函数节流和函数防抖为了解决类似需求应运而生的,有兴趣的可以了解一下
    2017-10-10
  • JSONObject与JSONArray使用方法解析

    JSONObject与JSONArray使用方法解析

    这篇文章主要介绍了JSONObject与JSONArray使用方法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-09-09
  • 使用js实现的简单拖拽效果

    使用js实现的简单拖拽效果

    本文给大家分享的是使用纯JS实现的简单的拖拽效果的插件,算是对自己javascript学习的一个小的检验,如果小伙伴们需要复杂的拖拽效果,还是考虑jQuery的draggable吧,更成熟一些。
    2015-03-03
  • JavaScript日期和时间的格式化及其它常用处理方法

    JavaScript日期和时间的格式化及其它常用处理方法

    这篇文章主要给大家介绍了关于JavaScript日期和时间的格式化及其它常用处理方法,JavaScript中可以使用Date对象来表示日期和时间,如果需要格式化日期和时间,可以使用Date对象的几个方法和一些字符串操作方法来实现,需要的朋友可以参考下
    2023-09-09
  • Javascript编程之继承实例汇总

    Javascript编程之继承实例汇总

    这篇文章主要介绍了Javascript编程之继承实现方法,结合实例形式分析汇总了五种常见的继承技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-11-11
  • JavaScript实现删除数组重复元素的5种常用高效算法总结

    JavaScript实现删除数组重复元素的5种常用高效算法总结

    这篇文章主要介绍了JavaScript实现删除数组重复元素的5种常用高效算法,结合实例形式总结分析了javascript删除数组重复元素的几种常见操作技巧,需要的朋友可以参考下
    2018-01-01
  • echarts饼图标签formatter使用及饼图自定义标签

    echarts饼图标签formatter使用及饼图自定义标签

    项目中有遇到需要使用饼图展示每种状态所占比例,去echarts官网学习了一番,下面这篇文章主要给大家介绍了关于echarts饼图标签formatter使用及饼图自定义标签的相关资料,需要的朋友可以参考下
    2022-12-12
  • layui导航栏二级菜单不显示问题及解决

    layui导航栏二级菜单不显示问题及解决

    这篇文章主要介绍了layui导航栏二级菜单不显示问题及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-05-05
  • js判断某个方法是否存在实例代码

    js判断某个方法是否存在实例代码

    这篇文章主要介绍了js判断某个方法是否存在的实例代码,可用于检测js中的方法是否可用,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-01-01

最新评论