@leafer/task 1.0.0-beta.9 → 1.0.0-rc.10
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 +117 -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.10",
|
|
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.10",
|
|
26
|
+
"@leafer/debug": "1.0.0-rc.10"
|
|
24
27
|
},
|
|
25
28
|
"devDependencies": {
|
|
26
|
-
"@leafer/interface": "1.0.0-
|
|
29
|
+
"@leafer/interface": "1.0.0-rc.10"
|
|
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,36 @@
|
|
|
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
|
|
18
|
+
|
|
19
|
+
protected timer: any
|
|
20
|
+
|
|
21
|
+
public get total(): number { return this.list.length + this.delayNumber }
|
|
15
22
|
|
|
16
|
-
|
|
17
|
-
private parallelSuccessNumber: number
|
|
23
|
+
public index = 0
|
|
18
24
|
|
|
19
|
-
public
|
|
20
|
-
private _isComplete: boolean
|
|
25
|
+
public delayNumber = 0 // 延迟执行任务
|
|
21
26
|
|
|
22
|
-
public get
|
|
23
|
-
|
|
24
|
-
|
|
27
|
+
public get finishedIndex(): number {
|
|
28
|
+
return this.isComplete ? 0 : this.index + this.parallelSuccessNumber
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public get remain(): number {
|
|
32
|
+
return this.isComplete ? this.total : this.total - this.finishedIndex
|
|
33
|
+
}
|
|
25
34
|
|
|
26
35
|
public get percent(): number {
|
|
27
36
|
const { total } = this
|
|
@@ -29,40 +38,64 @@ export class TaskProcessor implements ITaskProcessor {
|
|
|
29
38
|
|
|
30
39
|
for (let i = 0; i < total; i++) {
|
|
31
40
|
if (i <= this.finishedIndex) {
|
|
32
|
-
runTime += this.list[i].
|
|
41
|
+
runTime += this.list[i].time
|
|
33
42
|
if (i === this.finishedIndex) totalTime = runTime
|
|
34
43
|
} else {
|
|
35
|
-
totalTime += this.list[i].
|
|
44
|
+
totalTime += this.list[i].time
|
|
36
45
|
}
|
|
37
46
|
}
|
|
38
47
|
|
|
39
|
-
return this.
|
|
48
|
+
return this.isComplete ? 1 : (runTime / totalTime)
|
|
40
49
|
}
|
|
41
50
|
|
|
42
|
-
|
|
43
|
-
|
|
51
|
+
|
|
52
|
+
constructor(config?: ITaskProcessorConfig) {
|
|
53
|
+
if (config) DataHelper.assign(this.config, config)
|
|
54
|
+
this.empty()
|
|
44
55
|
}
|
|
45
56
|
|
|
46
|
-
|
|
57
|
+
// list
|
|
47
58
|
|
|
48
|
-
public
|
|
49
|
-
|
|
50
|
-
}
|
|
59
|
+
public add(taskCallback: IFunction, options?: ITaskOptions | number): ITaskItem {
|
|
60
|
+
let start: boolean, parallel: boolean, time: number, delay: number
|
|
51
61
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
62
|
+
const task = new TaskItem(taskCallback)
|
|
63
|
+
task.parent = this
|
|
55
64
|
|
|
65
|
+
if (typeof options === 'number') {
|
|
66
|
+
delay = options
|
|
67
|
+
} else if (options) {
|
|
68
|
+
parallel = options.parallel
|
|
69
|
+
start = options.start
|
|
70
|
+
time = options.time
|
|
71
|
+
delay = options.delay
|
|
72
|
+
}
|
|
56
73
|
|
|
57
|
-
|
|
58
|
-
if (
|
|
59
|
-
|
|
74
|
+
if (time) task.time = time
|
|
75
|
+
if (parallel === false) task.parallel = false
|
|
76
|
+
|
|
77
|
+
if (delay === undefined) {
|
|
78
|
+
this.push(task, start)
|
|
79
|
+
} else {
|
|
80
|
+
this.delayNumber++
|
|
81
|
+
setTimeout(() => {
|
|
82
|
+
if (this.delayNumber) {
|
|
83
|
+
this.delayNumber--
|
|
84
|
+
this.push(task, start)
|
|
85
|
+
}
|
|
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 {
|
|
@@ -70,23 +103,27 @@ export class TaskProcessor implements ITaskProcessor {
|
|
|
70
103
|
this.parallelSuccessNumber = 0
|
|
71
104
|
this.list = []
|
|
72
105
|
this.parallelList = []
|
|
106
|
+
this.delayNumber = 0
|
|
73
107
|
}
|
|
74
108
|
|
|
109
|
+
// control
|
|
110
|
+
|
|
75
111
|
public start(): void {
|
|
76
|
-
this.
|
|
77
|
-
|
|
78
|
-
|
|
112
|
+
if (!this.running) {
|
|
113
|
+
this.running = true
|
|
114
|
+
this.isComplete = false
|
|
115
|
+
this.run()
|
|
116
|
+
}
|
|
79
117
|
}
|
|
80
118
|
|
|
81
119
|
public pause(): void {
|
|
82
|
-
clearTimeout(this.
|
|
83
|
-
this.
|
|
120
|
+
clearTimeout(this.timer)
|
|
121
|
+
this.timer = null
|
|
122
|
+
this.running = false
|
|
84
123
|
}
|
|
85
124
|
|
|
86
125
|
public resume(): void {
|
|
87
|
-
this.
|
|
88
|
-
this._isComplete = false
|
|
89
|
-
this.run()
|
|
126
|
+
this.start()
|
|
90
127
|
}
|
|
91
128
|
|
|
92
129
|
public skip(): void {
|
|
@@ -95,45 +132,22 @@ export class TaskProcessor implements ITaskProcessor {
|
|
|
95
132
|
}
|
|
96
133
|
|
|
97
134
|
public stop(): void {
|
|
98
|
-
|
|
99
|
-
this.
|
|
100
|
-
this.
|
|
101
|
-
this.list.forEach(item => {
|
|
102
|
-
item.complete()
|
|
103
|
-
})
|
|
135
|
+
this.isComplete = true
|
|
136
|
+
this.list.forEach(task => { if (!task.isComplete) task.cancel() })
|
|
137
|
+
this.pause()
|
|
104
138
|
this.empty()
|
|
105
139
|
}
|
|
106
140
|
|
|
141
|
+
// run
|
|
107
142
|
|
|
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
|
|
143
|
+
protected run(): void {
|
|
144
|
+
if (!this.running) return
|
|
131
145
|
|
|
132
146
|
this.setParallelList()
|
|
133
147
|
|
|
134
148
|
if (this.parallelList.length > 1) {
|
|
135
149
|
|
|
136
|
-
this.
|
|
150
|
+
this.runParallelTasks()
|
|
137
151
|
|
|
138
152
|
} else {
|
|
139
153
|
|
|
@@ -144,6 +158,10 @@ export class TaskProcessor implements ITaskProcessor {
|
|
|
144
158
|
|
|
145
159
|
protected runTask(): void {
|
|
146
160
|
const task = this.list[this.index]
|
|
161
|
+
if (!task) {
|
|
162
|
+
this.nextTask() // 存在延时任务
|
|
163
|
+
return
|
|
164
|
+
}
|
|
147
165
|
task.run().then(() => {
|
|
148
166
|
|
|
149
167
|
this.onTask(task)
|
|
@@ -156,20 +174,31 @@ export class TaskProcessor implements ITaskProcessor {
|
|
|
156
174
|
})
|
|
157
175
|
}
|
|
158
176
|
|
|
159
|
-
protected
|
|
160
|
-
this.parallelList.forEach(task =>
|
|
161
|
-
|
|
177
|
+
protected runParallelTasks(): void {
|
|
178
|
+
this.parallelList.forEach(task => this.runParallelTask(task))
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
protected runParallelTask(task: ITaskItem): void {
|
|
182
|
+
task.run().then(() => {
|
|
162
183
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
184
|
+
this.onTask(task)
|
|
185
|
+
this.fillParallelTask()
|
|
186
|
+
|
|
187
|
+
}).catch(error => {
|
|
188
|
+
this.onParallelError(error)
|
|
168
189
|
})
|
|
169
190
|
}
|
|
170
191
|
|
|
192
|
+
private nextTask(): void {
|
|
193
|
+
if (this.total === this.finishedIndex) {
|
|
194
|
+
this.onComplete()
|
|
195
|
+
} else {
|
|
196
|
+
this.timer = setTimeout(() => this.run())
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
171
200
|
protected setParallelList(): void {
|
|
172
|
-
let task:
|
|
201
|
+
let task: ITaskItem
|
|
173
202
|
|
|
174
203
|
this.parallelList = []
|
|
175
204
|
this.parallelSuccessNumber = 0
|
|
@@ -189,8 +218,7 @@ export class TaskProcessor implements ITaskProcessor {
|
|
|
189
218
|
|
|
190
219
|
|
|
191
220
|
protected fillParallelTask(): void {
|
|
192
|
-
|
|
193
|
-
let task: TaskItem
|
|
221
|
+
let task: ITaskItem
|
|
194
222
|
const parallelList = this.parallelList
|
|
195
223
|
|
|
196
224
|
// 完成一个任务
|
|
@@ -203,24 +231,15 @@ export class TaskProcessor implements ITaskProcessor {
|
|
|
203
231
|
|
|
204
232
|
if (parallelList.length) {
|
|
205
233
|
|
|
206
|
-
if (!this.
|
|
234
|
+
if (!this.running) return
|
|
207
235
|
|
|
208
236
|
if (nextIndex < this.total) {
|
|
209
237
|
|
|
210
238
|
task = this.list[nextIndex]
|
|
211
239
|
|
|
212
|
-
if (task.parallel) {
|
|
213
|
-
|
|
240
|
+
if (task && task.parallel) {
|
|
214
241
|
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
|
-
|
|
242
|
+
this.runParallelTask(task)
|
|
224
243
|
}
|
|
225
244
|
|
|
226
245
|
}
|
|
@@ -234,27 +253,19 @@ export class TaskProcessor implements ITaskProcessor {
|
|
|
234
253
|
}
|
|
235
254
|
}
|
|
236
255
|
|
|
237
|
-
|
|
238
|
-
if (this.total === this.finishedIndex) {
|
|
239
|
-
this.onComplete()
|
|
240
|
-
} else {
|
|
241
|
-
this._timer = setTimeout(() => this.run(), 0)
|
|
242
|
-
}
|
|
243
|
-
}
|
|
256
|
+
// event
|
|
244
257
|
|
|
245
|
-
|
|
258
|
+
protected onComplete(): void {
|
|
246
259
|
this.stop()
|
|
247
260
|
if (this.config.onComplete) this.config.onComplete()
|
|
248
261
|
}
|
|
249
262
|
|
|
250
|
-
|
|
263
|
+
protected onTask(task: ITaskItem): void {
|
|
251
264
|
task.complete()
|
|
252
265
|
if (this.config.onTask) this.config.onTask()
|
|
253
266
|
}
|
|
254
267
|
|
|
255
|
-
|
|
256
|
-
debug.error('ParallelError')
|
|
257
|
-
|
|
268
|
+
protected onParallelError(error: unknown): void {
|
|
258
269
|
// 并行变串行, 以便下次重试
|
|
259
270
|
this.parallelList.forEach(task => {
|
|
260
271
|
task.parallel = false
|
|
@@ -265,13 +276,12 @@ export class TaskProcessor implements ITaskProcessor {
|
|
|
265
276
|
this.onError(error)
|
|
266
277
|
}
|
|
267
278
|
|
|
268
|
-
|
|
279
|
+
protected onError(error: unknown): void {
|
|
269
280
|
this.pause()
|
|
270
281
|
if (this.config.onError) this.config.onError(error)
|
|
271
282
|
}
|
|
272
283
|
|
|
273
284
|
public destroy(): void {
|
|
274
|
-
this.
|
|
275
|
-
this.config = {}
|
|
285
|
+
this.stop()
|
|
276
286
|
}
|
|
277
287
|
}
|
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 };
|