@leafer/task 1.0.0-beta.9 → 1.0.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +8 -5
- package/src/TaskItem.ts +17 -7
- package/src/TaskProcessor.ts +116 -107
- package/types/index.d.ts +54 -0
package/package.json
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leafer/task",
|
|
3
|
-
"version": "1.0.0-
|
|
3
|
+
"version": "1.0.0-rc.2",
|
|
4
4
|
"description": "@leafer/task",
|
|
5
5
|
"author": "Chao (Leafer) Wan",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"main": "src/index.ts",
|
|
8
|
+
"types": "types/index.d.ts",
|
|
8
9
|
"files": [
|
|
9
|
-
"src"
|
|
10
|
+
"src",
|
|
11
|
+
"types",
|
|
12
|
+
"dist"
|
|
10
13
|
],
|
|
11
14
|
"repository": {
|
|
12
15
|
"type": "git",
|
|
@@ -19,10 +22,10 @@
|
|
|
19
22
|
"leaferjs"
|
|
20
23
|
],
|
|
21
24
|
"dependencies": {
|
|
22
|
-
"@leafer/math": "1.0.0-
|
|
23
|
-
"@leafer/debug": "1.0.0-
|
|
25
|
+
"@leafer/math": "1.0.0-rc.2",
|
|
26
|
+
"@leafer/debug": "1.0.0-rc.2"
|
|
24
27
|
},
|
|
25
28
|
"devDependencies": {
|
|
26
|
-
"@leafer/interface": "1.0.0-
|
|
29
|
+
"@leafer/interface": "1.0.0-rc.2"
|
|
27
30
|
}
|
|
28
31
|
}
|
package/src/TaskItem.ts
CHANGED
|
@@ -1,30 +1,35 @@
|
|
|
1
|
-
import { IFunction } from '@leafer/interface'
|
|
1
|
+
import { IFunction, ITaskItem } from '@leafer/interface'
|
|
2
2
|
import { IncrementId } from '@leafer/math'
|
|
3
|
+
import { Debug } from '@leafer/debug'
|
|
3
4
|
|
|
4
5
|
import { TaskProcessor } from './TaskProcessor'
|
|
5
6
|
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
const debug = Debug.get('TaskProcessor')
|
|
9
|
+
export class TaskItem implements ITaskItem {
|
|
8
10
|
|
|
9
11
|
readonly id: number
|
|
10
12
|
|
|
11
13
|
public parent: TaskProcessor
|
|
12
14
|
|
|
13
|
-
public parallel
|
|
15
|
+
public parallel = true
|
|
16
|
+
public time = 1 // 预估任务需要运行的时间, 毫秒为单位
|
|
17
|
+
|
|
14
18
|
public isComplete: boolean
|
|
19
|
+
public isCancel: boolean
|
|
15
20
|
|
|
16
21
|
private task: IFunction
|
|
17
22
|
|
|
18
|
-
public taskTime = 1 // 预估任务需要运行的时间, 毫秒为单位
|
|
19
|
-
|
|
20
23
|
constructor(task?: IFunction) {
|
|
21
24
|
this.id = IncrementId.create(IncrementId.TASK)
|
|
22
25
|
this.task = task
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
async run(): Promise<void> {
|
|
26
|
-
|
|
27
|
-
await this.task()
|
|
29
|
+
try {
|
|
30
|
+
if (this.task && !this.isComplete && this.parent.running) await this.task()
|
|
31
|
+
} catch (error) {
|
|
32
|
+
debug.error(error)
|
|
28
33
|
}
|
|
29
34
|
}
|
|
30
35
|
|
|
@@ -34,4 +39,9 @@ export class TaskItem {
|
|
|
34
39
|
this.task = null
|
|
35
40
|
}
|
|
36
41
|
|
|
42
|
+
public cancel(): void {
|
|
43
|
+
this.isCancel = true
|
|
44
|
+
this.complete()
|
|
45
|
+
}
|
|
46
|
+
|
|
37
47
|
}
|
package/src/TaskProcessor.ts
CHANGED
|
@@ -1,27 +1,38 @@
|
|
|
1
|
-
import { IFunction, ITaskProcessor, ITaskProcessorConfig } from '@leafer/interface'
|
|
1
|
+
import { IFunction, ITaskProcessor, ITaskProcessorConfig, ITaskOptions, ITaskItem } from '@leafer/interface'
|
|
2
2
|
import { DataHelper } from '@leafer/data'
|
|
3
|
-
import { Debug } from '@leafer/debug'
|
|
4
3
|
|
|
5
4
|
import { TaskItem } from './TaskItem'
|
|
6
5
|
|
|
7
6
|
|
|
8
|
-
const debug = Debug.get('TaskProcessor')
|
|
9
|
-
|
|
10
7
|
export class TaskProcessor implements ITaskProcessor {
|
|
11
8
|
|
|
12
9
|
public config: ITaskProcessorConfig = { parallel: 6 }
|
|
13
10
|
|
|
14
|
-
|
|
11
|
+
protected list: ITaskItem[] = []
|
|
12
|
+
|
|
13
|
+
protected parallelList: ITaskItem[]
|
|
14
|
+
protected parallelSuccessNumber: number
|
|
15
|
+
|
|
16
|
+
public running = false
|
|
17
|
+
public isComplete = true
|
|
15
18
|
|
|
16
|
-
|
|
17
|
-
private parallelSuccessNumber: number
|
|
19
|
+
protected timer: any
|
|
18
20
|
|
|
19
|
-
public get
|
|
20
|
-
|
|
21
|
+
public get total(): number {
|
|
22
|
+
return this.list.length + this.delayNumber
|
|
23
|
+
}
|
|
21
24
|
|
|
22
|
-
public
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
public index = 0
|
|
26
|
+
|
|
27
|
+
public delayNumber = 0 // 延迟执行任务
|
|
28
|
+
|
|
29
|
+
public get finishedIndex(): number {
|
|
30
|
+
return this.isComplete ? 0 : this.index + this.parallelSuccessNumber
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public get remain(): number {
|
|
34
|
+
return this.isComplete ? this.total : this.total - this.finishedIndex
|
|
35
|
+
}
|
|
25
36
|
|
|
26
37
|
public get percent(): number {
|
|
27
38
|
const { total } = this
|
|
@@ -29,40 +40,62 @@ export class TaskProcessor implements ITaskProcessor {
|
|
|
29
40
|
|
|
30
41
|
for (let i = 0; i < total; i++) {
|
|
31
42
|
if (i <= this.finishedIndex) {
|
|
32
|
-
runTime += this.list[i].
|
|
43
|
+
runTime += this.list[i].time
|
|
33
44
|
if (i === this.finishedIndex) totalTime = runTime
|
|
34
45
|
} else {
|
|
35
|
-
totalTime += this.list[i].
|
|
46
|
+
totalTime += this.list[i].time
|
|
36
47
|
}
|
|
37
48
|
}
|
|
38
49
|
|
|
39
|
-
return this.
|
|
50
|
+
return this.isComplete ? 1 : (runTime / totalTime)
|
|
40
51
|
}
|
|
41
52
|
|
|
42
|
-
|
|
43
|
-
|
|
53
|
+
|
|
54
|
+
constructor(config?: ITaskProcessorConfig) {
|
|
55
|
+
if (config) DataHelper.assign(this.config, config)
|
|
56
|
+
this.empty()
|
|
44
57
|
}
|
|
45
58
|
|
|
46
|
-
|
|
59
|
+
// list
|
|
47
60
|
|
|
48
|
-
public
|
|
49
|
-
|
|
50
|
-
}
|
|
61
|
+
public add(taskCallback: IFunction, options?: ITaskOptions | number): ITaskItem {
|
|
62
|
+
let start: boolean, parallel: boolean, time: number, delay: number
|
|
51
63
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
64
|
+
const task = new TaskItem(taskCallback)
|
|
65
|
+
task.parent = this
|
|
66
|
+
|
|
67
|
+
if (typeof options === 'number') {
|
|
68
|
+
delay = options
|
|
69
|
+
} else if (options) {
|
|
70
|
+
parallel = options.parallel
|
|
71
|
+
start = options.start
|
|
72
|
+
time = options.time
|
|
73
|
+
delay = options.delay
|
|
74
|
+
}
|
|
55
75
|
|
|
76
|
+
if (time) task.time = time
|
|
77
|
+
if (parallel === false) task.parallel = false
|
|
56
78
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
79
|
+
if (delay === undefined) {
|
|
80
|
+
this.push(task, start)
|
|
81
|
+
} else {
|
|
82
|
+
this.delayNumber++
|
|
83
|
+
setTimeout(() => {
|
|
84
|
+
this.delayNumber--
|
|
85
|
+
this.push(task, start)
|
|
86
|
+
}, delay)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
this.isComplete = false
|
|
90
|
+
|
|
91
|
+
return task
|
|
60
92
|
}
|
|
61
93
|
|
|
62
|
-
protected
|
|
63
|
-
this.
|
|
64
|
-
this.
|
|
65
|
-
|
|
94
|
+
protected push(task: ITaskItem, start?: boolean): void {
|
|
95
|
+
this.list.push(task)
|
|
96
|
+
if (start !== false && !this.timer) {
|
|
97
|
+
this.timer = setTimeout(() => this.start())
|
|
98
|
+
}
|
|
66
99
|
}
|
|
67
100
|
|
|
68
101
|
protected empty(): void {
|
|
@@ -72,21 +105,24 @@ export class TaskProcessor implements ITaskProcessor {
|
|
|
72
105
|
this.parallelList = []
|
|
73
106
|
}
|
|
74
107
|
|
|
108
|
+
// control
|
|
109
|
+
|
|
75
110
|
public start(): void {
|
|
76
|
-
this.
|
|
77
|
-
|
|
78
|
-
|
|
111
|
+
if (!this.running) {
|
|
112
|
+
this.running = true
|
|
113
|
+
this.isComplete = false
|
|
114
|
+
this.run()
|
|
115
|
+
}
|
|
79
116
|
}
|
|
80
117
|
|
|
81
118
|
public pause(): void {
|
|
82
|
-
clearTimeout(this.
|
|
83
|
-
this.
|
|
119
|
+
clearTimeout(this.timer)
|
|
120
|
+
this.timer = null
|
|
121
|
+
this.running = false
|
|
84
122
|
}
|
|
85
123
|
|
|
86
124
|
public resume(): void {
|
|
87
|
-
this.
|
|
88
|
-
this._isComplete = false
|
|
89
|
-
this.run()
|
|
125
|
+
this.start()
|
|
90
126
|
}
|
|
91
127
|
|
|
92
128
|
public skip(): void {
|
|
@@ -95,45 +131,22 @@ export class TaskProcessor implements ITaskProcessor {
|
|
|
95
131
|
}
|
|
96
132
|
|
|
97
133
|
public stop(): void {
|
|
98
|
-
|
|
99
|
-
this.
|
|
100
|
-
this.
|
|
101
|
-
this.list.forEach(item => {
|
|
102
|
-
item.complete()
|
|
103
|
-
})
|
|
134
|
+
this.isComplete = true
|
|
135
|
+
this.list.forEach(task => { if (!task.isComplete) task.cancel() })
|
|
136
|
+
this.pause()
|
|
104
137
|
this.empty()
|
|
105
138
|
}
|
|
106
139
|
|
|
140
|
+
// run
|
|
107
141
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
this.push(new TaskItem(taskCallback), taskTime)
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
public addParallel(taskCallback: IFunction, taskTime?: number): void {
|
|
114
|
-
const task = new TaskItem(taskCallback)
|
|
115
|
-
task.parallel = true
|
|
116
|
-
this.push(task, taskTime)
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
public addEmpty(callback?: IFunction): void {
|
|
120
|
-
this.push(new TaskItem(callback))
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
private push(task: TaskItem, taskTime?: number): void {
|
|
124
|
-
if (taskTime) task.taskTime = taskTime
|
|
125
|
-
task.parent = this
|
|
126
|
-
this.list.push(task)
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
private run(): void {
|
|
130
|
-
if (!this._running) return
|
|
142
|
+
protected run(): void {
|
|
143
|
+
if (!this.running) return
|
|
131
144
|
|
|
132
145
|
this.setParallelList()
|
|
133
146
|
|
|
134
147
|
if (this.parallelList.length > 1) {
|
|
135
148
|
|
|
136
|
-
this.
|
|
149
|
+
this.runParallelTasks()
|
|
137
150
|
|
|
138
151
|
} else {
|
|
139
152
|
|
|
@@ -144,6 +157,10 @@ export class TaskProcessor implements ITaskProcessor {
|
|
|
144
157
|
|
|
145
158
|
protected runTask(): void {
|
|
146
159
|
const task = this.list[this.index]
|
|
160
|
+
if (!task) {
|
|
161
|
+
this.nextTask() // 存在延时任务
|
|
162
|
+
return
|
|
163
|
+
}
|
|
147
164
|
task.run().then(() => {
|
|
148
165
|
|
|
149
166
|
this.onTask(task)
|
|
@@ -156,20 +173,31 @@ export class TaskProcessor implements ITaskProcessor {
|
|
|
156
173
|
})
|
|
157
174
|
}
|
|
158
175
|
|
|
159
|
-
protected
|
|
160
|
-
this.parallelList.forEach(task =>
|
|
161
|
-
|
|
176
|
+
protected runParallelTasks(): void {
|
|
177
|
+
this.parallelList.forEach(task => this.runParallelTask(task))
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
protected runParallelTask(task: ITaskItem): void {
|
|
181
|
+
task.run().then(() => {
|
|
182
|
+
|
|
183
|
+
this.onTask(task)
|
|
184
|
+
this.fillParallelTask()
|
|
162
185
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
}).catch(error => {
|
|
166
|
-
this.onParallelError(error)
|
|
167
|
-
})
|
|
186
|
+
}).catch(error => {
|
|
187
|
+
this.onParallelError(error)
|
|
168
188
|
})
|
|
169
189
|
}
|
|
170
190
|
|
|
191
|
+
private nextTask(): void {
|
|
192
|
+
if (this.total === this.finishedIndex) {
|
|
193
|
+
this.onComplete()
|
|
194
|
+
} else {
|
|
195
|
+
this.timer = setTimeout(() => this.run())
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
171
199
|
protected setParallelList(): void {
|
|
172
|
-
let task:
|
|
200
|
+
let task: ITaskItem
|
|
173
201
|
|
|
174
202
|
this.parallelList = []
|
|
175
203
|
this.parallelSuccessNumber = 0
|
|
@@ -189,8 +217,7 @@ export class TaskProcessor implements ITaskProcessor {
|
|
|
189
217
|
|
|
190
218
|
|
|
191
219
|
protected fillParallelTask(): void {
|
|
192
|
-
|
|
193
|
-
let task: TaskItem
|
|
220
|
+
let task: ITaskItem
|
|
194
221
|
const parallelList = this.parallelList
|
|
195
222
|
|
|
196
223
|
// 完成一个任务
|
|
@@ -203,24 +230,15 @@ export class TaskProcessor implements ITaskProcessor {
|
|
|
203
230
|
|
|
204
231
|
if (parallelList.length) {
|
|
205
232
|
|
|
206
|
-
if (!this.
|
|
233
|
+
if (!this.running) return
|
|
207
234
|
|
|
208
235
|
if (nextIndex < this.total) {
|
|
209
236
|
|
|
210
237
|
task = this.list[nextIndex]
|
|
211
238
|
|
|
212
|
-
if (task.parallel) {
|
|
213
|
-
|
|
239
|
+
if (task && task.parallel) {
|
|
214
240
|
parallelList.push(task)
|
|
215
|
-
|
|
216
|
-
task.run().then(() => {
|
|
217
|
-
|
|
218
|
-
this.onTask(task)
|
|
219
|
-
this.fillParallelTask()
|
|
220
|
-
}).catch(error => {
|
|
221
|
-
this.onParallelError(error)
|
|
222
|
-
})
|
|
223
|
-
|
|
241
|
+
this.runParallelTask(task)
|
|
224
242
|
}
|
|
225
243
|
|
|
226
244
|
}
|
|
@@ -234,27 +252,19 @@ export class TaskProcessor implements ITaskProcessor {
|
|
|
234
252
|
}
|
|
235
253
|
}
|
|
236
254
|
|
|
237
|
-
|
|
238
|
-
if (this.total === this.finishedIndex) {
|
|
239
|
-
this.onComplete()
|
|
240
|
-
} else {
|
|
241
|
-
this._timer = setTimeout(() => this.run(), 0)
|
|
242
|
-
}
|
|
243
|
-
}
|
|
255
|
+
// event
|
|
244
256
|
|
|
245
|
-
|
|
257
|
+
protected onComplete(): void {
|
|
246
258
|
this.stop()
|
|
247
259
|
if (this.config.onComplete) this.config.onComplete()
|
|
248
260
|
}
|
|
249
261
|
|
|
250
|
-
|
|
262
|
+
protected onTask(task: ITaskItem): void {
|
|
251
263
|
task.complete()
|
|
252
264
|
if (this.config.onTask) this.config.onTask()
|
|
253
265
|
}
|
|
254
266
|
|
|
255
|
-
|
|
256
|
-
debug.error('ParallelError')
|
|
257
|
-
|
|
267
|
+
protected onParallelError(error: unknown): void {
|
|
258
268
|
// 并行变串行, 以便下次重试
|
|
259
269
|
this.parallelList.forEach(task => {
|
|
260
270
|
task.parallel = false
|
|
@@ -265,13 +275,12 @@ export class TaskProcessor implements ITaskProcessor {
|
|
|
265
275
|
this.onError(error)
|
|
266
276
|
}
|
|
267
277
|
|
|
268
|
-
|
|
278
|
+
protected onError(error: unknown): void {
|
|
269
279
|
this.pause()
|
|
270
280
|
if (this.config.onError) this.config.onError(error)
|
|
271
281
|
}
|
|
272
282
|
|
|
273
283
|
public destroy(): void {
|
|
274
|
-
this.
|
|
275
|
-
this.config = {}
|
|
284
|
+
this.stop()
|
|
276
285
|
}
|
|
277
286
|
}
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { ITaskProcessor, ITaskProcessorConfig, ITaskItem, IFunction, ITaskOptions } from '@leafer/interface';
|
|
2
|
+
|
|
3
|
+
declare class TaskProcessor implements ITaskProcessor {
|
|
4
|
+
config: ITaskProcessorConfig;
|
|
5
|
+
protected list: ITaskItem[];
|
|
6
|
+
protected parallelList: ITaskItem[];
|
|
7
|
+
protected parallelSuccessNumber: number;
|
|
8
|
+
running: boolean;
|
|
9
|
+
isComplete: boolean;
|
|
10
|
+
protected timer: any;
|
|
11
|
+
get total(): number;
|
|
12
|
+
index: number;
|
|
13
|
+
delayNumber: number;
|
|
14
|
+
get finishedIndex(): number;
|
|
15
|
+
get remain(): number;
|
|
16
|
+
get percent(): number;
|
|
17
|
+
constructor(config?: ITaskProcessorConfig);
|
|
18
|
+
add(taskCallback: IFunction, options?: ITaskOptions | number): ITaskItem;
|
|
19
|
+
protected push(task: ITaskItem, start?: boolean): void;
|
|
20
|
+
protected empty(): void;
|
|
21
|
+
start(): void;
|
|
22
|
+
pause(): void;
|
|
23
|
+
resume(): void;
|
|
24
|
+
skip(): void;
|
|
25
|
+
stop(): void;
|
|
26
|
+
protected run(): void;
|
|
27
|
+
protected runTask(): void;
|
|
28
|
+
protected runParallelTasks(): void;
|
|
29
|
+
protected runParallelTask(task: ITaskItem): void;
|
|
30
|
+
private nextTask;
|
|
31
|
+
protected setParallelList(): void;
|
|
32
|
+
protected fillParallelTask(): void;
|
|
33
|
+
protected onComplete(): void;
|
|
34
|
+
protected onTask(task: ITaskItem): void;
|
|
35
|
+
protected onParallelError(error: unknown): void;
|
|
36
|
+
protected onError(error: unknown): void;
|
|
37
|
+
destroy(): void;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
declare class TaskItem implements ITaskItem {
|
|
41
|
+
readonly id: number;
|
|
42
|
+
parent: TaskProcessor;
|
|
43
|
+
parallel: boolean;
|
|
44
|
+
time: number;
|
|
45
|
+
isComplete: boolean;
|
|
46
|
+
isCancel: boolean;
|
|
47
|
+
private task;
|
|
48
|
+
constructor(task?: IFunction);
|
|
49
|
+
run(): Promise<void>;
|
|
50
|
+
complete(): void;
|
|
51
|
+
cancel(): void;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export { TaskItem, TaskProcessor };
|