Files
Monopoly/extensions/app/assets/lib/task/task.ts
2026-03-30 09:39:59 +08:00

440 lines
9.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
interface IHandle {
(next: (data?: any) => boolean, retry: (timeout?: number) => Promise<boolean>, end: (data?: any) => boolean): void
}
interface IFinish<T> {
(results?: T, success?: boolean): any
}
export interface ITask<T extends Array<any> = any[]> {
readonly results: Readonly<T>;
size(): number;
add(handle: IHandle): this;
start(finish?: IFinish<T> | Function): this;
stop(): boolean;
isRunning(): boolean;
}
/**
* 顺序执行
*/
export class Sync<T extends Array<any>> implements ITask<T> {
private running = false;
private index: number = -1;
private list: IHandle[] = [];
private finish: IFinish<T> | Function = null;
/**
* 每个handle的返回值通过next或end存储
*/
public results: T = [] as T;
/**
* 任务数量
* @returns
*/
public size(): number {
return this.list.length;
}
/**
* 添加一个任务
* @param handle
* @returns
*/
public add(handle: IHandle) {
this.list.push(handle);
this.results.push(undefined);
return this;
}
/**
* 开始执行所有任务
* @param finish 执行完毕回调
* @returns
*/
public start(finish?: IFinish<T> | Function) {
if (this.running) {
return this;
}
this.running = true;
this.index = -1;
this.finish = finish;
this.next(this.index);
return this;
}
/**
* 停止所有任务
* @returns
*/
public stop(): boolean {
if (!this.running) {
return false;
}
this.running = false;
if (this.finish) {
this.finish(this.results, false);
}
return true;
}
/**
* 是否正在执行
* @returns
*/
public isRunning() {
return this.running;
}
/**
* @deprecated
* @returns
*/
public isStop() {
return !this.running;
}
private end(data?: any): boolean {
if (!this.running) {
return false;
}
if (typeof data !== 'undefined') {
this.results[this.index] = data;
}
this.running = false;
if (this.finish) {
this.finish(this.results, true);
}
return true;
}
private next(index: number, data?: any): boolean {
if (!this.running) {
return false;
}
if (index !== this.index) return false;
if (typeof data !== 'undefined') {
this.results[this.index] = data;
}
if (++this.index < this.list.length) {
this.retry(this.index);
} else {
this.end();
}
return true;
}
private retry(index: number): boolean {
if (!this.running) {
return false;
}
if (index !== this.index) return false;
const handle = this.list[index];
handle && handle(
(data?: any) => this.next(index, data),
(timeout = 0) => {
return new Promise(resolve => {
if (timeout > 0) {
setTimeout(() => {
resolve(this.retry(index));
}, timeout * 1000);
} else {
resolve(this.retry(index));
}
});
},
(data?: any) => this.end(data)
);
return true;
}
}
/**
* 同时执行
*/
export class ASync<T extends Array<any>> implements ITask<T> {
private running = false;
private count: number = 0;
private list: IHandle[] = [];
private finish: IFinish<T> | Function = null;
/**
* 每个handle的返回值通过next或end存储
*/
public results: T = [] as T;
/**
* 任务数量
* @returns
*/
public size(): number {
return this.list.length;
}
/**
* 添加一个任务
* @param handle
* @returns
*/
public add(handle: IHandle) {
this.list.push(handle);
this.results.push(undefined);
if (this.running) {
this.retry(this.list.length - 1);
}
return this;
}
/**
* 开始执行所有任务
* @param finish 执行完毕回调
* @returns
*/
public start(finish?: IFinish<T> | Function) {
if (this.running) {
return this;
}
this.running = true;
this.count = 0;
this.finish = finish;
if (this.list.length) {
for (let index = 0; index < this.list.length; index++) {
this.retry(index);
}
} else {
this.end && this.end(this.count);
}
return this;
}
/**
* 停止所有任务
* @returns
*/
public stop(): boolean {
if (!this.running) {
return false;
}
this.running = false;
if (this.finish) {
this.finish(this.results, false);
}
return true;
}
/**
* 是否正在执行
* @returns
*/
public isRunning() {
return this.running;
}
/**
* @deprecated
* @returns
*/
public isStop() {
return !this.running;
}
private end(index: number, data?: any): boolean {
if (!this.running) {
return false;
}
if (index >= 0 && index < this.results.length) {
if (this.results[index] || this.results[index] === null) return false;
this.results[index] = typeof data !== 'undefined' ? data : null;
}
this.running = false;
if (this.finish) {
this.finish(this.results, true);
}
return true;
}
private next(index: number, data?: any): boolean {
if (!this.running) {
return false;
}
if (index >= 0 && index < this.results.length) {
if (this.results[index] || this.results[index] === null) return false;
this.results[index] = typeof data !== 'undefined' ? data : null;
}
if (++this.count === this.list.length) {
this.end && this.end(this.count);
}
return true;
}
private retry(index: number): boolean {
if (!this.running) {
return false;
}
const handle = this.list[index];
handle && handle(
(data?: any) => this.next(index, data),
(timeout = 0) => {
return new Promise(resolve => {
if (timeout > 0) {
setTimeout(() => {
resolve(this.retry(index));
}, timeout * 1000);
} else {
resolve(this.retry(index));
}
});
},
(data?: any) => this.end(index, data)
);
return true;
}
}
export class Any<T extends Array<any>> implements ITask<T> {
private task = new Sync();
/**
* 每个handle的返回值通过next或end存储
*/
public get results(): T {
return this.task.results as T;
}
/**
* 任务数量
* @returns
*/
public size() {
return this.task.size();
}
/**
* 添加一个任务
* @param handle
* @returns
*/
public add(handles: IHandle | IHandle[]) {
if (handles instanceof Array) {
const async = new ASync();
handles.forEach(handle => async.add(handle));
this.task.add(async.start.bind(async));
} else {
this.task.add(handles);
}
return this;
}
/**
* 开始执行所有任务
* @param finish 执行完毕回调
* @returns
*/
public start(finish?: IFinish<T> | Function) {
this.task.start(finish);
return this;
}
/**
* 停止所有任务
* @returns
*/
public stop() {
return this.task.stop();
}
/**
* 是否正在执行
* @returns
*/
public isRunning() {
return this.task.isRunning();
}
/**
* @deprecated
* @returns
*/
public isStop() {
return this.task.isStop();
}
}
interface IExecuteCallBack {
(retry: (timeout?: number) => void): void
}
const task = {
/**
* 任务顺序执行
*/
createSync<T extends Array<any>>(): Sync<T> {
return new Sync<T>();
},
/**
* 任务同时执行
*/
createASync<T extends Array<any>>(): ASync<T> {
return new ASync<T>();
},
/**
* 根据参数指定执行顺序
* @example
* createAny()
* .add(1).add(2).add(3).add(4)
* .add([5,6,7])
* .add(8)
* 执行顺序1234依次执行然后同时执行567最后执行8
*/
createAny<T extends Array<any>>() {
return new Any<T>();
},
/**
* 执行单个任务
*/
execute(fun: IExecuteCallBack, retryMax = -1, retryFinish?: Function) {
fun(function retry(timeout = 0) {
if (retryMax === 0) return retryFinish && retryFinish();
retryMax = retryMax > 0 ? retryMax - 1 : retryMax;
if (timeout > 0) {
setTimeout(() => task.execute(fun, retryMax, retryFinish), timeout * 1000);
} else {
task.execute(fun, retryMax, retryFinish);
}
});
}
};
export default task;