JS如何优雅的中断正在执行的异步函数

在 JavaScript 里,若要优雅地中断正在执行的异步函数,可依据不同的异步实现方式采用不同的方法,下面详细介绍几种常见情况。

1. 使用 AbortController 中断 fetch 请求

AbortController 是一个内置于浏览器和 Node.js 中的 API,能用于取消 fetch 请求等异步操作。

javascript 复制代码
const controller = new AbortController();
const signal = controller.signal;

// 模拟一个 fetch 请求
fetch('https://example.com/api/data', { signal })
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => {
    if (error.name === 'AbortError') {
      console.log('请求已被取消');
    } else {
      console.error('请求出错:', error);
    }
  });

// 在需要的时候取消请求
controller.abort();

2. 在自定义异步函数中使用 AbortController

若你有自定义的异步函数,也能结合 AbortController 来实现中断功能。

javascript 复制代码
function customAsyncFunction(signal) {
  return new Promise((resolve, reject) => {
    const intervalId = setInterval(() => {
      console.log('异步操作正在执行...');
      if (signal.aborted) {
        clearInterval(intervalId);
        reject(new DOMException('操作已被取消', 'AbortError'));
      }
    }, 1000);
  });
}

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

customAsyncFunction(signal)
  .then(() => console.log('异步操作完成'))
  .catch(error => {
    if (error.name === 'AbortError') {
      console.log('异步操作已被取消');
    } else {
      console.error('异步操作出错:', error);
    }
  });

// 在需要的时候取消操作
setTimeout(() => {
  controller.abort();
}, 3000);

当然也可以使用一个变量来控制自定义异步函数的中断,这是一种较为基础且直观的方式。下面是使用变量来控制异步函数中断的示例代码:

javascript 复制代码
function customAsyncFunction() {
    let isAborted = false;

    return {
        promise: new Promise((resolve, reject) => {
            const intervalId = setInterval(() => {
                console.log('异步操作正在执行...');
                if (isAborted) {
                    clearInterval(intervalId);
                    reject(new Error('操作已被取消'));
                }
            }, 1000);
        }),
        abort: () => {
            isAborted = true;
        }
    };
}

const asyncTask = customAsyncFunction();

asyncTask.promise
   .then(() => console.log('异步操作完成'))
   .catch(error => {
        console.error('异步操作出错:', error.message);
    });

// 在需要的时候取消操作
setTimeout(() => {
    asyncTask.abort();
}, 3000);

使用变量控制和 AbortController 对比

  • 使用变量控制

    • 优点:简单直接,不需要额外了解新的 API,适合小型项目或者简单的异步控制场景。
    • 缺点:缺乏标准化,在不同的异步函数中可能需要重复实现类似的逻辑,代码的可维护性和扩展性较差。当项目规模变大,管理多个异步操作的中断状态会变得复杂。
  • 使用 AbortController

    • 优点 :是 JavaScript 官方标准化的 API,具有统一的使用方式和错误处理机制。可以在不同的异步操作(如 fetch 请求、自定义异步函数等)中复用,增强了代码的可维护性和一致性。在与第三方库或框架集成时,也更容易与其他使用 AbortController 的代码进行交互。
    • 缺点 :需要额外学习 AbortController 的使用方法,对于初学者来说可能有一定的学习成本。

使用变量控制能满足基本的异步函数中断需求,但在复杂的项目中,AbortController 是更优雅和推荐的选择。

3. 使用 Promise.race 实现超时中断

你可以利用 Promise.race 来实现超时中断异步操作。

javascript 复制代码
function asyncOperation() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve('操作完成');
    }, 5000);
  });
}

function timeout(ms) {
  return new Promise((_, reject) => {
    setTimeout(() => {
      reject(new Error('操作超时'));
    }, ms);
  });
}

Promise.race([asyncOperation(), timeout(3000)])
  .then(result => console.log(result))
  .catch(error => console.error(error.message));

以上这些方法能帮助你在不同场景下优雅地中断正在执行的异步函数。

相关推荐
Csvn1 小时前
Monorepo 迁移血泪史:从 Multi-Repo 到 Turborepo,这 3 个坑我帮你踩完了
前端
星栈1 小时前
Dioxus 多页面怎么做:`dioxus-router`、嵌套路由、`Outlet` 和页面组织,一篇给你讲顺
前端·rust·前端框架
用户987409238871 小时前
用 Remotion + edge-tts 打造中文教学视频全自动流水线
前端
风骏时光牛马1 小时前
Less前端工程化实战:变量混合器与项目样式分层落地
前端
假如让我当三天老蒯2 小时前
Options API(选项式 API) 和 Composition API(组合式 API)
前端·vue.js·面试
SameX2 小时前
iOS 独立开发实践:用 MapKit + 像素渲染实现 Citywalk 轨迹地图 App「雁过留痕」
前端
_柳青杨2 小时前
一文吃透 Node.js 事件循环:从原理到 Node 20+ 重大变更
javascript·后端
skyey2 小时前
页面加载时,深色模式闪白的问题解决
前端
IT_陈寒2 小时前
Java 并行流把我坑惨了,这6小时加班值了
前端·人工智能·后端
anOnion12 小时前
构建无障碍组件之Menu Button pattern
前端·html·交互设计