yuumi-request
Version:
request queue for browser
130 lines (110 loc) • 3.33 kB
text/typescript
export enum JobStatus {
WAITING,
PENDING,
FULLFILLED,
REJECT,
CANCELED
}
export type ResolveFun = (value: unknown) => any
export type RejectFun = (reason?: any) => any
interface JobInterface {
addTask: (resolve: ResolveFun, reject?: RejectFun) => Job
run: () => Promise<unknown>
cancel: () => void
}
interface JobLisenters {
success: Function[]
fail: Function[]
complete: Function[]
cancel: Function[]
}
export class Job implements JobInterface {
private status: JobStatus = JobStatus.WAITING
private tasks:[ResolveFun, RejectFun?][]
private abort?: RejectFun
private complete?: Function
constructor(tasks?:[ResolveFun, RejectFun?][]) {
this.tasks = tasks || []
}
/**
* 添加一个任务到工作
* @param resolve Promise.resolve
* @param reject Promise.reject
* @returns Job
*/
addTask(resolve: ResolveFun, reject?: RejectFun): Job {
this.tasks.push([resolve, reject])
return this
}
/**
* 运行Job
* @returns Promise
*/
run(): Promise<unknown> {
if (this.status === JobStatus.CANCELED) return Promise.reject({ code: -1, message: "job be canceled." })
if (this.status !== JobStatus.WAITING) return Promise.reject({ code: -1, message: "job is runing." })
this.status = JobStatus.PENDING
const token = new Promise((resolve, reject) => {
this.complete = () => {
this.dispatch("complete")
resolve(void 0)
}
this.abort = () => reject({ code: -1, message: "job be canceled." })
})
let promise = Promise.resolve()
this.tasks.forEach(([resolve, reject]) => {
if (typeof reject !== 'function') {
reject = (reason) => Promise.reject(reason)
}
promise = promise.then((value) => {
// 防止调用cancel后,后续还在走resolve
if (this.status === JobStatus.CANCELED) {
return Promise.reject({ code: -1, message: "job be canceled." })
}
return resolve(value)
}, reject)
})
promise = promise.then((value) => {
this.status = JobStatus.FULLFILLED
this.dispatch("success", value)
return value
}, (reason) => {
this.status = JobStatus.REJECT
this.dispatch("fail", reason)
return Promise.reject(reason)
})
return Promise.race([ promise, token ]).finally(() => {
this.complete && this.complete
})
}
cancel() {
if (this.status !== JobStatus.WAITING && this.status !== JobStatus.PENDING) return
this.abort && this.abort()
this.status = JobStatus.CANCELED
this.dispatch("cancel")
}
/** 事件监听 */
private lisenters: JobLisenters & Record<string, Function[]> = {
success: [],
fail: [],
complete: [],
cancel: []
}
dispatch(name: string, value?: unknown) {
if (!this.lisenters[name]) return
this.lisenters[name].forEach((item) => item(value))
}
addLisenter(name: string, lisenter: (value?: unknown) => void) {
if (!this.lisenters[name]) {
this.lisenters[name] = []
}
this.lisenters[name].push(lisenter)
}
removeListenr(name: string, lisenter: (value?: unknown) => void) {
if (!this.lisenters[name]) return
const index = this.lisenters[name].findIndex((item) => item === lisenter)
if (index >= 0) {
this.lisenters[name].splice(index, 1)
}
}
}