AbortController创建一个可中断的异步任务执行函数---【已解决】

发布时间 2023-10-11 09:10:07作者: 凿壁偷光,集思广益

1、需求背景

使用异步操作(promise)或者多个循环时,遇到不能及时中断操作,回收资源时

2、代码

/**
 * 创建一个可中断的异步任务执行函数。
 * @param {function} taskFunction - 要执行的异步任务函数,接受一个 AbortSignal 参数用于中断。
 * @returns {object} 包含执行任务和中断任务的函数的对象。
 */
function createAbortFunction(taskFunction) {
  let abortController = null; // 用于控制任务的中断
  let signal = null; // 用于传递给任务函数的 AbortSignal

  /**
   * 执行异步任务
   * @param {...any} args - 传递给任务函数的参数
   * @returns {Promise} 异步任务的结果
   */
  async function execute(...args) {
    abortController = new AbortController(); // 创建一个新的 AbortController
    signal = abortController.signal; // 获取与控制器相关的 AbortSignal
    try {
      return await taskFunction(...args, signal); // 执行任务函数并传递 AbortSignal
    } catch (error) {
      if (signal.aborted) {
        const msg = {
          fn: taskFunction,
          ...signal.reason,
        };
        console.log('任务主动中断', msg);
        throw error;
      } else {
        console.error('其他错误处理:', error); // 如果出现其他错误,记录错误信息并抛出错误
        throw error;
      }
    }
  }

  /**
   * 中断当前执行的任务
   */
  function abort(reason = '主动中断') {
    if (abortController) {
      abortController.abort({
        mas: reason,
        type: 'ABORT_ACTION',
      });
    }
  }

  return { execute, abort }; // 返回包含执行任务和中断任务函数的对象
}

2、使用案例

导入
// 导入 createAbortFunction
import { createAbortFunction } from './your-abort-function-module';

// 模拟一个异步任务函数,接受 AbortSignal 并在中断时抛出 AbortError
async function exampleTask(params1, params2, signal) {
  let arr = [];
  for (let i = 0; i < 5; i++) {
    await new Promise(resolve => setTimeout(resolve, 1000));

    // 注意!!!!!必须添加中断标记
    if (signal.aborted) {
      throw signal;
    }
    console.log('params2 -->', params2, 'params1 -->', params1, 'i -->', i);

    arr.push(i);
  }
  return arr;
}

// 使用 createAbortFunction 创建可中断任务执行器
const { execute, abort } = createAbortFunction(exampleTask);

(async () => {
  try {
    console.log('任务开始执行...');
    const result = await execute('aa', 'bb');
    console.log('任务完成:', result);
  } catch (error) {
    console.error('任务失败:', error);
  }
})();

// 在需要中断任务的地方调用
setTimeout(() => {
  // 可传一个中断原因
  abort('用户主动中断');
}, 2500);

3、最终结果

对于业务中长请求或者多个异步请求存在前后关联的场景下,可以有效的控制顺序以及执行过程