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

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

大家好,欢迎来到IT知识分享网。

一、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(); } }

完整板:

 
  
<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()即可终止正在挂起的请求。

完整版:

 
  
  • {{item.name}}
<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>

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 
  
    ' promise.cancel = () => controller.abort(); 
  

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

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

在 React 组件中使用getCharacter

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

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

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

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

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

编辑

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

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

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

编辑切换为居中

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

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

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

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

编辑切换为居中

添加图片注释,不超过 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; }

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

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

编辑

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

总结

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

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

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/175025.html

(0)
上一篇 2025-03-31 08:10
下一篇 2025-03-31 08:20

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信