【JavaScript】使用 AbortController 对象中断 fetch 的文本流传输

AbortController

正如我们所知道的,fetch 返回一个 promise。JavaScript 通常并没有"中止" promise 的概念。那么我们怎样才能取消一个正在执行的 fetch 呢?例如,如果用户在我们网站上的操作表明不再需要某个执行中的 fetch。

为此有一个特殊的内建对象:AbortController。它不仅可以中止 fetch,还可以中止其他异步任务。

用法非常简单。

创建一个控制器(controller)

js 复制代码
let controller = new AbortController();

控制器是一个极其简单的对象。

它具有单个方法 abort(),

和单个属性 signal,我们可以在这个属性上设置事件监听器。

当 abort() 被调用时:

js 复制代码
controller.signal // 就会触发 abort 事件。
controller.signal.aborted // 属性变为 true。

通常,我们需要处理两部分:

一部分是通过在 controller.signal 上添加一个监听器,来执行可取消操作。

另一部分是触发取消:在需要的时候调用 controller.abort()。

这是完整的示例(目前还没有 fetch):

js 复制代码
let controller = new AbortController();
let signal = controller.signal;

// 执行可取消操作部分
// 获取 "signal" 对象,
// 并将监听器设置为在 controller.abort() 被调用时触发
signal.addEventListener('abort', () => alert("abort!"));

// 另一部分,取消(在之后的任何时候):
controller.abort(); // 中止!

// 事件触发,signal.aborted 变为 true
alert(signal.aborted); // true

正如我们所看到的,AbortController 只是在 abort() 被调用时传递 abort 事件的一种方式。

我们可以自己在代码中实现相同类型的事件监听,而不需要 AbortController 对象。

但是有价值的是,fetch 知道如何与 AbortController 对象一起工作。它们是集成在一起的。

与 fetch 一起使用

为了能够取消 fetch,请将 AbortController 的 signal 属性作为 fetch 的一个可选参数(option)进行传递:

js 复制代码
let controller = new AbortController();
fetch(url, {
  signal: controller.signal
});

fetch 方法知道如何与 AbortController 一起工作。它会监听 signal 上的 abort 事件。

现在,想要中止 fetch,调用 controller.abort() 即可:

js 复制代码
controller.abort();

我们完成啦:fetch 从 signal 获取了事件并中止了请求。

当一个 fetch 被中止,它的 promise 就会以一个 error AbortError reject,因此我们应该对其进行处理,例如在 try...catch 中。

这是完整的示例,其中 fetch 在 1 秒后中止:

js 复制代码
// 1 秒后中止
let controller = new AbortController();
setTimeout(() => controller.abort(), 1000);

try {
  let response = await fetch('/article/fetch-abort/demo/hang', {
    signal: controller.signal
  });
} catch(err) {
  if (err.name == 'AbortError') { // handle abort()
    alert("Aborted!");
  } else {
    throw err;
  }
}

参考

AbortController.AbortController()------MDN
Fetch:中止(Abort)

相关推荐
JerryXZR6 天前
Javascript 高级事件编程 - Axios & fetch
javascript·ecmascript·axios·fetch
Bug从此不上门13 天前
Nuxt3之使用lighthouse性能测试及性能优化实操
前端·javascript·性能优化·vue·fetch·nuxt3
aimmon2 个月前
Superset二次开发之Git篇git fetch 异常信息汇总
git·二次开发·fetch·bi·superset
@PHARAOH4 个月前
WHAT - xmlhttprequest vs fetch vs wretch
前端·javascript·网络·http·fetch
起风的秋天@5 个月前
使用【AbortController】终止请求
前端·fetch
SunFlower9145 个月前
axios设置 responseType为 “stream“流式获取后端数据
axios·xmlhttprequest·stream·fetch·responsetype·readablestream·流式接口
witton6 个月前
使用Beego创建API项目并自动化文档
自动化·api·swagger·fetch·beego·cors·bee
南城巷陌7 个月前
前端发送请求之fetch跟axios的区别
前端·axios·网络请求·fetch
酒茶白开水7 个月前
Vue2 基础四前后端交互
vue·axios·async·promise·fetch·url·await