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