import {nanoid} from "nanoid"; export enum TASK_ERRORS { INVALID_STATUS = "TASK_ERRORS_INVALID_STATUS" } export enum TASK_STATUS { READY = "READY", MOVING = "MOVING", PROCESSING = "PROCESSING", SUCCESS = "SUCCESS", FAIL = "FAIL" } export declare interface TaskConfig { level?: number, isPreCondition?: boolean, parentTaskId?: string, asyncFunction: (Task) => Promise, onReady?: (task: Task, message?: any) => Promise onMoving?: (task: Task, message?: any) => Promise onSuccess?: (task: Task, message?: any) => Promise onFail?: (task: Task, message?: any) => Promise onProcessing?: (task: Task, message?: any) => Promise } const generateTaskId = () => { if (typeof crypto !== "undefined" && crypto && crypto?.randomUUID) return crypto.randomUUID() + crypto.randomUUID() return nanoid(72)//兼容RN端 } /** * ## Task **任务实体** * parentTaskId用来处理多层级任务的问题 * 例如 如果父级任务是前置任务 且 包含了多个子级任务 这个时候 子级任务是永远不会执行 因为有且只能有一个前置任务 * 前置任务里面的子级任务排在前置任务后面 所以不会执行 * 这个时候需要用这个parentTaskId进行关系绑定 * **/ export class Task { /** 任务ID **/ public readonly id: string = generateTaskId() /** 父级任务ID **/ public readonly parentTaskId: string = "" /** 任务执行的异步函数 **/ public readonly asyncFunction: (Task) => Promise = async () => ({}) /** 任务优先等级 **/ public readonly level: number = 0 /** 任务失败次数 **/ public failTimes: number = 0 /** 任务执行成功结果 **/ public result: Array = [] /** 任务执行失败报错信息 **/ public error: any = undefined /** 任务状态 **/ public status: TASK_STATUS = TASK_STATUS.READY /* 是否前置条件任务 如果为true的时候 无论设置并发数量多少 都会先执行这个任务(多个前置条件任务按照level排序) 且当前只执行该任务 */ public isPreCondition: boolean = false /** 任务准备状态回调 会被触发多次 **/ private readonly onReady: (task: Task, message?: any) => Promise = async () => ({}) /** 任务被移动的回调 移动期间不允许对任务进行其他操作 例如从成功的队列移动到失败的队列 **/ private readonly onMoving: (task: Task, message?: any) => Promise = async () => ({}) /** 任务执行成功回调 **/ private readonly onSuccess: (task: Task, message?: any) => Promise = async () => ({}) /** 任务执行失败回调 **/ private readonly onFail: (task: Task, message?: any) => Promise = async () => ({}) /** 任务执行中的回调 **/ private readonly onProcessing: (task: Task, message?: any) => Promise = async () => ({}) constructor(config: TaskConfig) { const { asyncFunction, level, onReady, onProcessing, onSuccess, onFail, onMoving, isPreCondition, parentTaskId } = config this.asyncFunction = asyncFunction ?? this.asyncFunction this.level = level ?? this.level this.onReady = onReady ?? this.onReady this.onProcessing = onProcessing ?? this.onProcessing this.onSuccess = onSuccess ?? this.onSuccess this.onFail = onFail ?? this.onFail this.onMoving = onMoving ?? this.onMoving this.isPreCondition = isPreCondition ?? false this.parentTaskId = parentTaskId ?? this.parentTaskId this.updateStatus(TASK_STATUS.READY) } /** 任务状态更新 **/ public async updateStatus(status: TASK_STATUS, message?: any): Promise { this.status = status switch (status) { case TASK_STATUS.READY: this.result = [] this.error = undefined this.onReady(this, message) break case TASK_STATUS.MOVING: this.onMoving(this, message) break case TASK_STATUS.PROCESSING: this.result = [] this.error = undefined this.onProcessing(this, message) break case TASK_STATUS.SUCCESS: this.result = message ?? [] this.onSuccess(this, ...(message ?? [])) break case TASK_STATUS.FAIL: await this.addFailTimes() this.error = message this.onFail(this, message) break } } /** 失败次数增加 **/ private async addFailTimes(): Promise { this.failTimes++ } /** 执行任务 **/ public async execute(): Promise { if (this.status !== TASK_STATUS.READY) throw new Error(TASK_ERRORS.INVALID_STATUS) await this.updateStatus(TASK_STATUS.PROCESSING) let result: any = [] try { await this.asyncFunction(this).then((...arg) => { result = arg }) await this.updateStatus(TASK_STATUS.SUCCESS, result) } catch (error) { await this.updateStatus(TASK_STATUS.FAIL, error) throw error instanceof Error ? error as Error : new Error(error as string) } return result } }