百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

停止javascript的ajax请求,取消axios请求,取消reactfetch请求

myzbx 2025-10-23 08:35 5 浏览

一、Ajax

原生里可以通过XMLHttpRequest对象上的abort方法来中断ajax。注意abort方法不能阻止向服务器发送请求,只能停止当前ajax请求。

停止javascript的ajax请求有两种方式

1. 设置超时时间让ajax自动断开

2. 手动去停止ajax请求,

核心是调用XMLHttpRequest对象上的abort方法

我们以jquery举例说明:

jquery的ajax对象的abort方法:调用abort后jquery会执行error的方法,抛出abort的异常信息,此时即可执行我们中断ajax后的操作。

var ajax = $.ajax({
'error':function(jqXHR, textStatus, errorThrown){
if(errorThrown != 'abort'){
//ajax被调用abort后执行的方法
alert('您的ajax方法被停止了');
        }
    }
})
 
ajax.abort();//停止ajax

原生JS

xmlHttp.open("POST","Url",true);
xmlHttp.onreadystatechange=function(){
 ...//得到响应之后的操作
}
xmlHttp.send();
//设置3秒钟后检查xmlHttp对象所发送的数据是否得到响应.
setTimeout("CheckRequest()","3000");
function CheckRequest(){
   //为4时代表请求完成了
   if(xmlHttp.readyState!=4){
     alert('数据响应超时');
     //关闭请求
     xmlHttp.close();
   }
}

完整板:

<div class="page" id="app">
    <button  class="get-msg">获取数据</button>
    <button  class="cancel">取消获取</button>
  </div>
<script>
  var currentAjax = null
    $('.get-msg').click(function () {
      currentAjax = $.ajax({
        type: 'GET',
        url: 'http://jsonplaceholder.typicode.com/comments',
        success: function (res) {
          console.log(res)
        },
        error: function (err) {
          console.log("获取失败")
        }
      })
    })
    $('.cancel').click(function () {
      if (currentAjax) {
        currentAjax.abort()
      }
    })
</script>

切记:不可用abort方法来作为终止对服务器的请求操作,只有当做在前端页面立刻停止执行ajax成功后的方法,因为你执行abort方法后,ajax很可能已经对服务端发送了请求,只是还未返回回馈信息而已。

二、Axios:

关键词:CancelToken、source、source.token

应用场景:tab页频繁切换,页面的切换,用于终止正在挂起的请求

axios 的 cancelToken

axios是一个主流的http请求库,它提供了两种取消请求的方式。

项目的如何应用

  • 配置参数
axios({
	method: 'post',
	url: url,
	withCredentials: false,
	params: params,
	data: data,
	cancelToken:data.cancelToken,
	headers: headerParam
}).then(resp => {
	resolve(resp)
}).catch(error => {
	reject(error)
})

在调用请求那传入令牌
cancelToken:data.cancelToken
data为传入的参数

调用接口前,传入上一步需要的令牌

let CancelToken = this.axios.CancelToken;this.source = CancelToken.source();data.cancelToken = this.source.token;

axios 在 main.js中挂载到了 实例中, data data 为请求的参数,this.source中有token令牌和取消请求的cancel方法

终止请求

cancelRequest(){
   this.source.cancel("异常信息,选填")
},

在发起新的请求的时候,执行一下this.source.cancel()即可终止正在挂起的请求。

完整版:

<body>
  <div class="page" id="app">
    <button @click="getMsg" class="get-msg">获取数据</button>
    <button @click="cancelGetMsg" class="cancel">取消获取</button>
    <ul>
      <li v-for="item in items">{{item.name}}</li>
    </ul>
  </div>
  <script>
  var app = new Vue({
    el: '#app',
    data: {
      message: 'Hello Vue!',
      items: [],
      cancel: null
    },
    methods: {
      getMsg () {
        let CancelToken = axios.CancelToken
        let self = this
        axios.get('http://jsonplaceholder.typicode.com/comments', {
          cancelToken: new CancelToken(function executor(c) {
            self.cancel = c
            console.log(c)
            // 这个参数 c 就是CancelToken构造函数里面自带的取消请求的函数,这里把该函数当参数用
          })
        }).then(res => {
          this.items = res.data
        }).catch(err => {
          console.log(err)
        })


        //手速够快就不用写这个定时器了,点击取消获取就可以看到效果了
        setTimeout(function () {
          //只要我们去调用了这个cancel()方法,没有完成请求的接口便会停止请求
          self.cancel()
        }, 100)
      },
      //cancelGetMsg 方法跟上面的setTimeout函数是一样的效果,因为手速不够快,哦不,是因为网速太快,导致我来不及点取消获取按钮,数据就获取成功了
      cancelGetMsg () {
        // 在这里去判断你的id 1 2 3,你默认是展示的tab1,点击的时候不管你上一个请求有没有执行完都去调用这个cancel(),
        this.cancel()
      }
    }
  })
  </script>
</body>


axios 的 cancelToken

axios是一个主流的http请求库,它提供了两种取消请求的方式。

  • 通过axios.CancelToken.source生成取消令牌token和取消方法cancel
const CancelToken = axios.CancelToken;
const source = CancelToken.source();

axios.get('/user/12345', {
 cancelToken: source.token
}).catch(function(thrown) {
 if (axios.isCancel(thrown)) {
 console.log('Request canceled', thrown.message);
  } else {
 // handle error
  }
});

axios.post('/user/12345', {
 name: 'new name'
}, {
 cancelToken: source.token
})

// cancel the request (the message parameter is optional)
source.cancel('Operation canceled by the user.');
通过axios.CancelToken构造函数生成取消函数
const CancelToken = axios.CancelToken;
let cancel;

axios.get('/user/12345', {
 cancelToken: new CancelToken(function executor(c) {
 // An executor function receives a cancel function as a parameter
 cancel = c;
  })
});

// cancel the request
cancel();

需要注意的是在catch中捕获异常时,应该使用axios.isCancel()判断当前请求是否是主动取消的,以此来区分普通的异常逻辑。

封装取消请求逻辑

上面有两种取消请求,用哪种都是可以的,这里使用第二种。

取消请求主要有两个场景:

  • 当请求方式method,请求路径url,请求参数(getparamspostdata)都相同时,可以视为同一个请求发送了多次,需要取消之前的请求
  • 当路由切换时,需要取消上个路由中未完成的请求

我们封装几个方法:

// 声明一个 Map 用于存储每个请求的标识 和 取消函数
const pending = new Map()
/**
 * 添加请求
 * @param {Object} config 
 */
const addPending = (config) => {
  const url = [
    config.method,
    config.url,
    qs.stringify(config.params),
    qs.stringify(config.data)
  ].join('&')
  config.cancelToken = config.cancelToken || new axios.CancelToken(cancel => {
    if (!pending.has(url)) { // 如果 pending 中不存在当前请求,则添加进去
      pending.set(url, cancel)
    }
  })
}
/**
 * 移除请求
 * @param {Object} config 
 */
const removePending = (config) => {
  const url = [
    config.method,
    config.url,
    qs.stringify(config.params),
    qs.stringify(config.data)
  ].join('&')
  if (pending.has(url)) { // 如果在 pending 中存在当前请求标识,需要取消当前请求,并且移除
    const cancel = pending.get(url)
    cancel(url)
    pending.delete(url)
  }
}
/**
 * 清空 pending 中的请求(在路由跳转时调用)
 */
export const clearPending = () => {
  for (const [url, cancel] of pending) {
    cancel(url)
  }
  pending.clear()
}

MapES6中一种新型的数据结构,本身提供了诸多方法,方便操作,适合当前场景。如果不熟悉的可以查看ECMAScript 6 入门。

在给config.cancelToken赋值的时候,需要判断当前请求是否已经在业务代码中使用了cancelToken

qs是一个专门用来转换对象和字符串参数的库,最初是由 TJ 创建并维护的,也是axios推荐使用的参数序列化库。这里我们的目的只是单纯的将参数对象转换为字符串方便拼接。

Map结构默认部署了Symbol.iterator属性,可以使用for...of循环直接获取键名和键值,当然你也可以使用for...in循环。

在 axios 拦截器中使用

主要的方法已经写好了,只需要添加到axios拦截器中就可以了。

axios.interceptors.request.use(config => {
  removePending(options) // 在请求开始前,对之前的请求做检查取消操作
  addPending(options) // 将当前请求添加到 pending 中
  // other code before request
  return config
}, error => {
  return Promise.reject(error)
})

axios.interceptors.response.use(response => {
  removePending(response) // 在请求结束后,移除本次请求
  return response
}, error => {
  if (axios.isCancel(error)) {
    console.log('repeated request: ' + error.message)
  } else {
    // handle error code
  }
  return Promise.reject(error)
})

clearPending()方法添加到vue路由钩子函数中

router.beforeEach((to, from, next) => {
  clearPending()
  // ...
  next()
})

三、fetch

以下是取消 Fetch 请求的基本步骤:

const controller = new AbortController();
const { signal } = controller;

fetch("http://localhost:8000", { signal }).then(response => {
    console.log(`Request 1 is complete!`);
}).catch(e => {
    console.warn(`Fetch 1 error: ${e.message}`);
});

// Abort request
controller.abort();

abort 调用时发生 AbortError,因此你可以通过比较错误名称来侦听 catch 中的中止操作。

}).catch(e => {
    if(e.name === "AbortError") {
        // We know it's been canceled!
    }
});

将相同的信号传递给多个 fetch 调用将会取消该信号的所有请求:

const controller = new AbortController();
const { signal } = controller;

fetch("http://localhost:8000", { signal }).then(response => {
    console.log(`Request 1 is complete!`);
}).catch(e => {
    console.warn(`Fetch 1 error: ${e.message}`);
});

fetch("http://localhost:8000", { signal }).then(response => {
    console.log(`Request 2 is complete!`);
}).catch(e => {
    console.warn(`Fetch 2 error: ${e.message}`);
});

// Wait 2 seconds to abort both requests
setTimeout(() => controller.abort(), 2000);

样板:

function abortableFetch(request, opts) {
  const controller = new AbortController();
  const signal = controller.signal;

  return {
    abort: () => controller.abort(),
    ready: fetch(request, { ...opts, signal })
  };
}

说实话,我对取消 Fetch 的方法并不感到兴奋。在理想的世界中,通过 Fetch 返回的 Promise 中的 .cancel() 会很酷,但是也会带来一些问题。无论如何,我为能够取消 Fetch 调用而感到高兴,你也应该如此!

使用AbortController来取消 fetch

AbortController 是 JavaScript 的最新版本中的特性,它是在 fetch 被实现之后出现的。 更好的消息是所有现代浏览器都支持它。

AbortController 包含一个 abort 方法。 它还包含一个可以传递给fetchsignal属性。 当调用 AbortController.abort 时,fetch请求就会被取消。

让我们在 getCharacterfetch请求中使用 AbortController 及其signal属性:

function getCharacter(id: number) {
  // 获取AbortController实例
  const controller = new AbortController();
  // 获取 signal属性
  const signal = controller.signal;
  const promise = new Promise(async (resolve) => {
    const response = await fetch(`https://swapi.dev/api/people/${id}/`, {
      method: "get",
      // 将 signal作为fetch的参数之一
      signal,
    });
    const data = await response.json();
    assertIsCharacter(data);
    resolve(data);
  });
  // 设置一个 取消函数
  promise.cancel = () => controller.abort();
  return promise;
}

我们从getCharacter函数中删除了async关键字,并将现有代码包装在一个新的Promise中。 当请求到数据后,我们使用resolve将数据抛出去。 我们在Promise中添加了一个cancel方法,该方法调用了AbortController.abort

包含 cancel 方法的 PromisegetCharacter 中被返回,以便我们在业务代码中可以使用它来取消请求。

保存代码查看界面效果,发现有一个类型错误:

// - Property 'cancel' does not exist on type 'Promise<unknown>'
promise.cancel = () => controller.abort();

让我们为Promisecancel 方法创建一个类型

interface PromiseWithCancel<T> extends Promise<T> {
  cancel: () => void;
}
// 使用 然使用类型断言来解决前面的类型错误
function getCharacter(id: number) {
  ...
  (promise as PromiseWithCancel<Character>).cancel = () => controller.abort();
  return promise as PromiseWithCancel<Character>;
}

在 React 组件中使用getCharacter

我们将把getCharacter返回的 promise 存储在一个名为query的状态变量中。

export function App() {
  const [status, setStatus] = React.useState<"loading" | "loaded" | "cancelled">("loading");
  const [data, setData] = React.useState<Character | undefined>(undefined);
  const [query, setQuery] = React.useState<PromiseWithCancel<Character> | undefined>(undefined);
  React.useEffect(() => {
    const q = getCharacter(1);
    setQuery(q);
    q.then((character) => {
      setData(character);
      setStatus("loaded");
    });
  }, []);
  ...

现在,当点击取消按钮的时候,我们调用 promise 中的cancle方法

<button
  onClick={() => {
    query?.cancel();
    setStatus("cancelled");
  }}
>
  Cancel
</button>

点击取消按钮后吗,我们看到发现’Cancelled‘文案被渲染出来了


编辑

添加图片注释,不超过 140 字(可选)


再通过谷歌开发者工具查看网络请求,发现请求也被取消了

编辑切换为居中

添加图片注释,不超过 140 字(可选)

捕获"取消请求"发生的错误

让我们再看看控制台,当请求被取消后,有错误被抛出了


编辑切换为居中

添加图片注释,不超过 140 字(可选)

我们可以使用 try catch 来包裹请求以便捕获错误

const promise = new Promise(async (resolve) => {
  try {
    const response = await fetch(`https://swapi.dev/api/people/${id}/`, {
      method: "get",
      signal,
    });
    const data = await response.json();
    assertIsCharacter(data);
    resolve(data);
  } catch (ex: unknown) {
    if (isAbortError(ex)) {
      console.log(ex.message);
    }
  }
});

isAbortError类型的函数如下

function isAbortError(error: any): error is DOMException {
  if (error && error.name === "AbortError") {
    return true;
  }
  return false;
}

现在当我们再次点击取消按钮,我们会在控制台收到一条消息提示而不是一个错误


编辑

添加图片注释,不超过 140 字(可选)


总结

可以将AbortController中的signal属性传递给fetch。 然后可以调用AbortController.abort取消请求。

取消 fetch 会引发一个错误,但可以使用try catch将其捕获。

相关推荐

如何设计一个优秀的电子商务产品详情页

加入人人都是产品经理【起点学院】产品经理实战训练营,BAT产品总监手把手带你学产品电子商务网站的产品详情页面无疑是设计师和开发人员关注的最重要的网页之一。产品详情页面是客户作出“加入购物车”决定的页面...

怎么在JS中使用Ajax进行异步请求?

大家好,今天我来分享一项JavaScript的实战技巧,即如何在JS中使用Ajax进行异步请求,让你的网页速度瞬间提升。Ajax是一种在不刷新整个网页的情况下与服务器进行数据交互的技术,可以实现异步加...

中小企业如何组建,管理团队_中小企业应当如何开展组织结构设计变革

前言写了太多关于产品的东西觉得应该换换口味.从码农到架构师,从前端到平面再到UI、UE,最后走向了产品这条不归路,其实以前一直再给你们讲.产品经理跟项目经理区别没有特别大,两个岗位之间有很...

前端监控 SDK 开发分享_前端监控系统 开源

一、前言随着前端的发展和被重视,慢慢的行业内对于前端监控系统的重视程度也在增加。这里不对为什么需要监控再做解释。那我们先直接说说需求。对于中小型公司来说,可以直接使用三方的监控,比如自己搭建一套免费的...

Ajax 会被 fetch 取代吗?Axios 怎么办?

大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发!今天给大家带来的主题是ajax、fetch...

前端面试题《AJAX》_前端面试ajax考点汇总

1.什么是ajax?ajax作用是什么?AJAX=异步JavaScript和XML。AJAX是一种用于创建快速动态网页的技术。通过在后台与服务器进行少量数据交换,AJAX可以使网页实...

Ajax 详细介绍_ajax

1、ajax是什么?asynchronousjavascriptandxml:异步的javascript和xml。ajax是用来改善用户体验的一种技术,其本质是利用浏览器内置的一个特殊的...

6款可替代dreamweaver的工具_替代powerdesigner的工具

dreamweaver对一个web前端工作者来说,再熟悉不过了,像我07年接触web前端开发就是用的dreamweaver,一直用到现在,身边的朋友有跟我推荐过各种更好用的可替代dreamweaver...

我敢保证,全网没有再比这更详细的Java知识点总结了,送你啊

接下来你看到的将是全网最详细的Java知识点总结,全文分为三大部分:Java基础、Java框架、Java+云数据小编将为大家仔细讲解每大部分里面的详细知识点,别眨眼,从小白到大佬、零基础到精通,你绝...

福斯《死侍》发布新剧照 &quot;小贱贱&quot;韦德被改造前造型曝光

时光网讯福斯出品的科幻片《死侍》今天发布新剧照,其中一张是较为罕见的死侍在被改造之前的剧照,其余两张剧照都是死侍在执行任务中的状态。据外媒推测,片方此时发布剧照,预计是为了给不久之后影片发布首款正式预...

2021年超详细的java学习路线总结—纯干货分享

本文整理了java开发的学习路线和相关的学习资源,非常适合零基础入门java的同学,希望大家在学习的时候,能够节省时间。纯干货,良心推荐!第一阶段:Java基础重点知识点:数据类型、核心语法、面向对象...

不用海淘,真黑五来到你身边:亚马逊15件热卖爆款推荐!

Fujifilm富士instaxMini8小黄人拍立得相机(黄色/蓝色)扫二维码进入购物页面黑五是入手一个轻巧可爱的拍立得相机的好时机,此款是mini8的小黄人特别版,除了颜色涂装成小黄人...

2025 年 Python 爬虫四大前沿技术:从异步到 AI

作为互联网大厂的后端Python爬虫开发,你是否也曾遇到过这些痛点:面对海量目标URL,单线程爬虫爬取一周还没完成任务;动态渲染的SPA页面,requests库返回的全是空白代码;好不容易...

最贱超级英雄《死侍》来了!_死侍超燃

死侍Deadpool(2016)导演:蒂姆·米勒编剧:略特·里斯/保罗·沃尼克主演:瑞恩·雷诺兹/莫蕾娜·巴卡林/吉娜·卡拉诺/艾德·斯克林/T·J·米勒类型:动作/...

停止javascript的ajax请求,取消axios请求,取消reactfetch请求

一、Ajax原生里可以通过XMLHttpRequest对象上的abort方法来中断ajax。注意abort方法不能阻止向服务器发送请求,只能停止当前ajax请求。停止javascript的ajax请求...