前端如何中断已发出的HTTP请求

308 阅读1分钟

fetch

使用AbortController在第二个参数中传入signal属性

const control = new AbortController()
const signal =  control.signal
fetch('https://juejin.cn/post/7026947170683076621', { signal }).then(res => {
    console.log(res);
    
}).catch(err => {
    console.log(err);
    
})
setTimeout(() => {
    control.abort() // DOMException: The user aborted a request.

}, 50);

axios

使用axios.CancelToken

// http.js  一般都会封装一个http.js文件做一些逻辑处理
// 响应拦截
httpInstance.interceptors.response.use(response => {}, error => {
    if(axios.isCancel(error)) {
        return  Promise.reject(error);
    } else {
        ...
    }
})
// axios实例上post方法
httpInstance.post(url, payload, _config) 


// *.vue中使用
import api from './api'
import axios from 'axios'

const CancelToken = axios.CancelToken
const source = CancelToken.source()

api.sendRequest(url, query, { cancelToken: source.token })
    .then(res => {})
    .catch(err => { 
        console.log(err) // Cancel {message: "user Canceled Token"}
    })
    
setTimeout(() => {
    source.cancel('user Canceled Token')
}, 50);

xhr

const xhr = new XMLHttpRequest()
xhr.open('GET', 'https://...', true)

xhr.onreadystatechange = () => { 
    if (xhr.readyState === 4) {
        ...
    }
} 
xhr.send();

// 调用abort方法取消即可
xhr.abort();

如何从外部退出一组异步任务,并且中断所有还未返回的请求

// 但是感觉非常不优雅,有没有大佬可以帮忙改一下/(ㄒoㄒ)/~~
class CreatAsyncJob {
    constructor(taskArr) {
        this.taskArr = taskArr
        this.responseArr = []
        this.abortFlag = false
    }
    async request()  {
        for(let t of this.taskArr) {
            if(this.abortFlag) {
                // this.taskArr === s
                // abort放在这里不会取消已发送的请求
                // 因为在第一次请求响应时间小于1000ms,第二次时候已经运行到 this.responseArr.push(await t.task()) 做等待了,允许到这里的时候是第三次了
                // this.taskArr.forEach(i => i.control.abort()) -->> 这条语句可能不起效
                return
            }
            this.responseArr.push(await t.task())
        }
    }
    abort()  {
        this.abortFlag = true
    }

}

function fetchJob(control) {
    return fetch('https://juejin.cn/post/7026947170683076621', { signal: control.signal })
}

const s = new Array(5).fill(null).map((item, idx, arr) => {
    const control = new AbortController()
    return {
        control,
        task: () => fetchJob(control)
    }
})
const jobs = new CreatAsyncJob(s)

jobs.request()
setTimeout(() => {
    jobs.abort()
    // abort放在这里就能取消已发送的请求
    s.forEach(i => i.control.abort())
    console.log(jobs.responseArr); // length: 1
    
}, 1000);