Skip to content

useQueue

useQueue 是一个通用的 任务队列管理 Hook,可用于控制请求并发、排队执行任务、失败重试等场景,特别适合导入导出、大批量操作等企业应用需求。

基础用法

typescript
import { useQueue } from '@yh-ui/request'

const {
  tasks, // 所有任务
  pendingTasks, // 待执行
  runningTasks, // 执行中
  completedTasks, // 已完成
  failedTasks, // 失败
  isRunning,
  add,
  start,
  pause,
  resume,
  clear,
  retry,
  retryAll
} = useQueue({
  concurrency: 3, // 最大并发数
  autoStart: false, // 是否自动开始
  continueOnError: false // 是否在任务失败时继续执行
})

配置项

参数类型默认值说明
concurrencynumber1最大并发执行任务数
autoStartbooleantrue添加任务后是否自动开始执行
continueOnErrorbooleanfalse单个任务失败时是否继续执行后续任务
onTaskComplete(task) => void-单个任务完成回调
onTaskError(task, error) => void-单个任务失败回调
onAllComplete(tasks) => void-全部任务完成回调

队列任务结构

typescript
interface QueueTask<T = unknown> {
  id: string
  key?: string // 任务去重 key
  task: () => Promise<T> // 实际执行函数
  priority?: number // 优先级(数字越大越先执行)
  status: 'pending' | 'running' | 'fulfilled' | 'rejected' | 'canceled'
  result?: T
  error?: Error
  metadata?: Record<string, unknown>
  createdAt: number
  startTime?: number
  endTime?: number
  delay?: number // 延迟执行时间(毫秒)
}

添加任务

typescript
// 添加一个请求任务
const taskId = add(
  async () => {
    const res = await request.get('/api/report/1')
    return res.data
  },
  {
    key: 'report-1', // 相同 key 可用于业务去重
    priority: 10, // 优先级,越大越先执行
    delay: 1000, // 延迟 1s 后执行
    metadata: { type: 'report' }
  }
)

// 开始执行队列
start()

控制并发

typescript
const { add, start, pause, resume, isRunning } = useQueue({
  concurrency: 5, // 最多同时执行 5 个任务
  autoStart: true
})

// 添加 100 个请求任务
for (let i = 0; i < 100; i++) {
  add(() => request.get(`/api/item/${i}`).then((res) => res.data))
}

错误与重试

typescript
const { failedTasks, retry, retryAll } = useQueue({
  concurrency: 2,
  continueOnError: true, // 单个任务失败时继续执行其他任务
  onTaskError: (task, error) => {
    console.error('任务失败:', task.id, error)
  },
  onAllComplete: (tasks) => {
    console.log('全部任务完成:', tasks.length)
  }
})

// 重试单个任务
retry(taskId)

// 重试所有失败任务
retryAll()

与请求结合

批量导出

typescript
const exportIds = ref<string[]>([])

const queue = useQueue({
  concurrency: 2,
  autoStart: true,
  onTaskComplete: (task) => {
    YhMessage.success(`导出成功: ${task.metadata?.name}`)
  },
  onTaskError: (task, error) => {
    YhMessage.error(`导出失败: ${task.metadata?.name}`)
  }
})

const startExport = () => {
  exportIds.value.forEach((id) => {
    queue.add(
      async () => {
        const res = await request.get('/api/export', { params: { id } })
        // 触发浏览器下载 ...
        return res.data
      },
      {
        key: id,
        priority: 1,
        metadata: { name: `任务 ${id}` }
      }
    )
  })
}

上传队列

typescript
const uploadQueue = useQueue({
  concurrency: 3,
  autoStart: true
})

const handleFiles = (files: FileList) => {
  Array.from(files).forEach((file) => {
    uploadQueue.add(
      async () => {
        const form = new FormData()
        form.append('file', file)
        const res = await request.post('/api/upload', form)
        return res.data
      },
      { key: file.name }
    )
  })
}

常用 API 一览

方法 / 状态说明
add(task, options)添加任务,返回任务 ID
remove(taskId)移除任务
clear()清空队列
start()开始执行队列
pause() / resume()暂停 / 恢复队列
cancel(taskId) / cancelAll()取消任务
retry(taskId) / retryAll()重试任务
getTask(taskId)根据任务 ID 获取任务
pendingTasks / runningTasks / completedTasks / failedTasks不同状态的任务列表
isRunning / isEmpty / isAllComplete队列整体状态
completedCount / totalCount已完成数量 / 总任务数

进阶:结合 useRequestQueue

源码中还提供了 useRequestQueue(未在本篇展开),在 useQueue 的基础上增加了对请求级别的封装,适合进一步抽象复杂业务。你可以直接组合 useQueue + request 完成大多数队列/并发场景。

Released under the MIT License.