中止一个或多个 Web 请求

ajax 有主动结束请求的方法 Ajax.abort
Axios CancelToken
fetch ws 没有主动结束请求的方法

使用js的一个方法AbortController

AbortController 是一个 JavaScript API,用于中止一个或多个 Web 请求。
提供了一种标准化的方式来取消异步操作。

AbortController 由两部分组成:

AbortController:控制器对象,用于发送中止信号
AbortSignal:信号对象,用于监听中止事件

在fetch中的使用

// 1. 创建 AbortController 实例
const controller = new AbortController();
const signal = controller.signal;

// 2. 将 signal 传递给可中止的操作
fetch('/api/data', { signal })
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(err => {
    if (err.name === 'AbortError') {
      console.log('请求被中止');
    } else {
      console.error('请求错误:', err);
    }
  });

// 3. 中止请求
controller.abort(); // 这会触发 AbortError

主要应用场景

取消 Fetch 请求
取消 Axios 请求
中止任何支持 signal 的异步操作
清理事件监听器
取消长时间运行的任务

与 Fetch API 结合使用

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

// 设置超时自动取消
const timeoutId = setTimeout(() => controller.abort(), 5000);

fetch('https://api.example.com/data', { signal })
  .then(response => {
    clearTimeout(timeoutId);
    return response.json();
  })
  .then(data => console.log(data))
  .catch(err => {
    if (err.name === 'AbortError') {
      console.log('请求超时被取消');
    } else {
      console.error('请求错误:', err);
    }
  });

与 Axios 结合使用

const controller = new AbortController();

axios.get('/api/data', {
  signal: controller.signal
})
.then(response => console.log(response.data))
.catch(err => {
  if (axios.isCancel(err)) {
    console.log('请求被取消:', err.message);
  } else {
    console.error('请求错误:', err);
  }
});

// 取消请求
controller.abort();

复用同一个信号

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

// 多个请求使用同一个信号
fetch('/api/data1', { signal });
fetch('/api/data2', { signal });
fetch('/api/data3', { signal });

// 一次性取消所有请求
controller.abort();

监听中止事件

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

signal.addEventListener('abort', () => {
  console.log('中止信号已触发');
  // 执行清理操作
});

controller.abort(); // 会触发上面的监听器

自定义可中止操作

function doTask(signal) {
  return new Promise((resolve, reject) => {
    const timeoutId = setTimeout(() => resolve('任务完成'), 5000);
    
    // 监听中止信号
    signal.addEventListener('abort', () => {
      clearTimeout(timeoutId);
      reject(new DOMException('任务被中止', 'AbortError'));
    });
    
    if (signal.aborted) {
      clearTimeout(timeoutId);
      reject(new DOMException('任务被中止', 'AbortError'));
    }
  });
}

const controller = new AbortController();
doTask(controller.signal)
  .then(console.log)
  .catch(err => {
    if (err.name === 'AbortError') {
      console.log('任务被手动中止');
    }
  });

// 2秒后中止任务
setTimeout(() => controller.abort(), 2000);

浏览器兼容性

现代浏览器(Chrome 66+, Firefox 57+, Safari 12.1+, Edge 16+)都支持
Node.js 从 v15.0.0 开始支持
对于旧环境可以使用 polyfill

在 AbortController 之前,常用的取消请求方式:

XMLHttpRequest 的 abort()
Axios 的 CancelToken

最佳实践

及时清理:不再需要的控制器应该被清理
错误处理:总是检查错误类型是否为 AbortError
避免内存泄漏:组件卸载时取消所有未完成的请求
合理使用:不要过度使用,只在必要时取消请求

http1 最多同时发送6个请求,也就是说 如果开了6ws, 那么页面上的任何接口的请求都发不出去

主动中断 XHR(fetch/axios)请求和SSE(Server-Sent Events)请求(笔记)

  1. fetch XHR 请求的主动中断
    使用 AbortController,fetch 原生支持 AbortController 来中断请求。
// 创建一个 AbortController 实例
const controller = new AbortController();
const signal = controller.signal;

// 发起 fetch 请求时传入 signal
fetch('https://jsonplaceholder.typicode.com/todos/1', { signal })
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(err => {
    if (err.name === 'AbortError') {
      console.log('请求被中断');
    } else {
      console.error('请求出错', err);
    }
  });

// 需要中断请求时调用
controller.abort();
  1. axios XHR 请求的主动中断
    2.1 使用 CancelToken(axios v0.22及以下)
import axios from 'axios';

const CancelToken = axios.CancelToken;
let cancel;

// 发起请求
axios.get('https://jsonplaceholder.typicode.com/todos/1', {
  cancelToken: new CancelToken(function executor(c) {
    cancel = c;
  })
}).then(res => {
  console.log(res.data);
}).catch(thrown => {
  if (axios.isCancel(thrown)) {
    console.log('请求被取消');
  } else {
    console.error('请求出错', thrown);
  }
});

// 需要中断请求时调用
cancel('手动取消请求');

2.2 axios v1.0+ 推荐用 AbortController

const controller = new AbortController();

axios.get('https://jsonplaceholder.typicode.com/todos/1', {
  signal: controller.signal
}).then(res => {
  console.log(res.data);
}).catch(err => {
  if (err.code === 'ERR_CANCELED') {
    console.log('请求被取消');
  } else {
    console.error('请求出错', err);
  }
});

// 需要中断请求时调用
controller.abort();
  1. SSE(Server-Sent Events)请求的主动中断
    SSE 通常用 EventSource 或自定义 fetch+流的方式实现。
    3.1 原生 EventSource
const es = new EventSource('/sse-url');
es.onmessage = (event) => {
  console.log('收到消息:', event.data);
};
// 需要中断时
es.close();

3.2 fetch+流(如你的 MyStream 实现)
你需要保存 AbortController 实例,并在需要时调用 abort()。

class MyStream {
  constructor() {
    this.controller = null;
    this.reader = null;
  }

  async getStream(url, onData, onEnd) {
    this.controller = new AbortController();
    const response = await fetch(url, { signal: this.controller.signal });
    const reader = response.body.getReader();
    this.reader = reader;

    // 读取流数据
    while (true) {
      const { value, done } = await reader.read();
      if (done) break;
      onData(value);
    }
    onEnd();
  }

  abortStream() {
    if (this.reader) this.reader.cancel();
    if (this.controller) this.controller.abort();
  }
}

// 使用
const stream = new MyStream();
stream.getStream('/sse-url', data => console.log(data), () => console.log('end'));
// 需要中断时
stream.abortStream();
  1. 结合 Vue 组件的实际用法
data() {
  return {
    controller: null,
  }
},
methods: {
  fetchData() {
    this.controller = new AbortController();
    fetch('/api/data', { signal: this.controller.signal })
      .then(res => res.json())
      .then(data => { /* ... */ })
      .catch(err => {
        if (err.name === 'AbortError') {
          console.log('请求被中断');
        }
      });
  },
  abortFetch() {
    if (this.controller) this.controller.abort();
  }
}

总结

fetch/axios v1+ 推荐用 AbortController,调用 controller.abort() 主动中断。
axios v0.22- 用 CancelToken。
SSE 用 EventSource.close() 或自定义流时用 AbortController 和 reader.cancel()。
高频请求场景,一定要保存 controller/reader 实例,及时中断不再需要的请求,避免资源泄漏和页面卡死。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值