Skip to content

Commit 80d9212

Browse files
committed
opt: indicator calc
1 parent 86359c6 commit 80d9212

File tree

4 files changed

+61
-134
lines changed

4 files changed

+61
-134
lines changed

src/Store.ts

Lines changed: 29 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import type { KLineData, VisibleRangeData } from './common/Data'
2020
import type VisibleRange from './common/VisibleRange'
2121
import type Coordinate from './common/Coordinate'
2222
import { getDefaultVisibleRange } from './common/VisibleRange'
23-
import TaskScheduler, { generateTaskId } from './common/TaskScheduler'
23+
import TaskScheduler from './common/TaskScheduler'
2424
import type Crosshair from './common/Crosshair'
2525
import type BarSpace from './common/BarSpace'
2626
import type { Period } from './common/Period'
@@ -308,7 +308,7 @@ export default class StoreImp implements Store {
308308
/**
309309
* Task scheduler
310310
*/
311-
private readonly _taskScheduler = new TaskScheduler()
311+
private readonly _taskScheduler: TaskScheduler
312312

313313
/**
314314
* Overlay
@@ -376,6 +376,13 @@ export default class StoreImp implements Store {
376376
if (isValid(decimalFold)) {
377377
this.setDecimalFold(decimalFold)
378378
}
379+
this._taskScheduler = new TaskScheduler(() => {
380+
this._chart.layout({
381+
measureWidth: true,
382+
update: true,
383+
buildYAxisTick: true
384+
})
385+
})
379386
}
380387

381388
setStyles (value: string | DeepPartial<Styles>): void {
@@ -577,14 +584,13 @@ export default class StoreImp implements Store {
577584
adjustFlag = true
578585
}
579586
}
580-
if (success) {
581-
if (adjustFlag) {
582-
this._adjustVisibleRange()
583-
this.setCrosshair(this._crosshair, { notInvalidate: true })
584-
const filterIndicators = this.getIndicatorsByFilter({})
585-
filterIndicators.forEach(indicator => {
586-
this._addIndicatorCalcTask(indicator, type)
587-
})
587+
if (success && adjustFlag) {
588+
this._adjustVisibleRange()
589+
this.setCrosshair(this._crosshair, { notInvalidate: true })
590+
const filterIndicators = this.getIndicatorsByFilter({})
591+
if (filterIndicators.length > 0) {
592+
this._calcIndicator(filterIndicators)
593+
} else {
588594
this._chart.layout({
589595
measureWidth: true,
590596
update: true,
@@ -699,7 +705,7 @@ export default class StoreImp implements Store {
699705
symbol: this._symbol,
700706
period: this._period,
701707
timestamp: null,
702-
callback: (data: KLineData[], more?: boolean) => {
708+
callback: (data: KLineData[], more?: DataLoadMore) => {
703709
this._loading = false
704710
this._addData(data, type, more)
705711
if (type === 'init') {
@@ -1123,38 +1129,16 @@ export default class StoreImp implements Store {
11231129
}
11241130
}
11251131

1126-
private _addIndicatorCalcTask (indicator: IndicatorImp, dataLoadType: DataLoadType): void {
1127-
indicator.onDataStateChange?.({
1128-
state: 'loading',
1129-
type: dataLoadType,
1130-
indicator
1131-
})
1132-
void this._taskScheduler.add<boolean>({
1133-
id: generateTaskId(indicator.id),
1134-
handler: async () => await indicator.calcImp(this._dataList).then(result => result)
1135-
}).then(result => {
1136-
if (result) {
1137-
this._chart.layout({
1138-
measureWidth: true,
1139-
update: true,
1140-
buildYAxisTick: true,
1141-
cacheYAxisWidth: dataLoadType !== 'init'
1142-
})
1143-
indicator.onDataStateChange?.({
1144-
state: 'ready',
1145-
type: dataLoadType,
1146-
indicator
1147-
})
1148-
}
1149-
}).catch((e: unknown) => {
1150-
if (e !== 'canceled') {
1151-
indicator.onDataStateChange?.({
1152-
state: 'error',
1153-
type: dataLoadType,
1154-
indicator
1155-
})
1156-
}
1157-
})
1132+
private _calcIndicator (data: IndicatorImp | IndicatorImp[]): void {
1133+
let indicators: IndicatorImp[] = []
1134+
indicators = indicators.concat(data)
1135+
if (indicators.length > 0) {
1136+
const tasks: Record<string, Promise<unknown>> = {}
1137+
indicators.forEach(indicator => {
1138+
tasks[indicator.id] = indicator.calcImp(this._dataList)
1139+
})
1140+
this._taskScheduler.add(tasks)
1141+
}
11581142
}
11591143

11601144
addIndicator (create: PickRequired<IndicatorCreate, 'id' | 'name'>, paneId: string, isStack: boolean): boolean {
@@ -1177,7 +1161,7 @@ export default class StoreImp implements Store {
11771161
paneIndicators.push(indicator)
11781162
this._indicators.set(paneId, paneIndicators)
11791163
this._sortIndicators(paneId)
1180-
this._addIndicatorCalcTask(indicator, 'init')
1164+
this._calcIndicator(indicator)
11811165
return true
11821166
}
11831167

@@ -1211,7 +1195,6 @@ export default class StoreImp implements Store {
12111195
const paneIndicators = this.getIndicatorsByPaneId(indicator.paneId)
12121196
const index = paneIndicators.findIndex(ins => ins.id === indicator.id)
12131197
if (index > -1) {
1214-
this._taskScheduler.remove(generateTaskId(indicator.id))
12151198
paneIndicators.splice(index, 1)
12161199
removed = true
12171200
}
@@ -1269,7 +1252,7 @@ export default class StoreImp implements Store {
12691252
sortFlag = true
12701253
}
12711254
if (calc) {
1272-
this._addIndicatorCalcTask(indicator, 'update')
1255+
this._calcIndicator(indicator)
12731256
} else {
12741257
if (draw) {
12751258
updateFlag = true

src/common/DataLoader.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ import type { Period } from './Period'
2020
export type DataLoadType = 'init' | 'forward' | 'backward' | 'update'
2121

2222
export type DataLoadMore = boolean | {
23-
backward: boolean
24-
forward: boolean
23+
backward?: boolean
24+
forward?: boolean
2525
}
2626

2727
export interface DataLoaderGetBarsParams {

src/common/TaskScheduler.ts

Lines changed: 30 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -12,101 +12,53 @@
1212
* limitations under the License.
1313
*/
1414

15+
import type Nullable from './Nullable'
1516
import { isValid } from './utils/typeChecks'
1617

17-
export function generateTaskId (...params: string[]): string {
18-
return params.join('_')
19-
}
20-
21-
interface Task<T> {
22-
id: string
23-
handler: () => Promise<T>
24-
}
25-
26-
type TaskRun = () => void
27-
28-
export type TaskRejectReason = 'canceled' | 'failed'
29-
30-
interface TaskWrapper {
31-
run: TaskRun
32-
reject: (reason?: TaskRejectReason) => void
33-
}
34-
35-
const DEFAULT_TASK_LIMIT = 5
18+
type TaskFinishedCallback = () => void
3619

3720
export default class TaskScheduler {
38-
private readonly _limit: number
39-
private _running = 0
40-
private _queue: TaskRun[] = []
41-
private readonly _taskMap = new Map<string, TaskWrapper>()
21+
private _holdingTasks: Nullable<Record<string, Promise<unknown>>> = null
4222

43-
constructor (limit?: number) {
44-
this._limit = limit ?? DEFAULT_TASK_LIMIT
45-
}
23+
private _running = false
4624

47-
async add<T> (task: Task<T>): Promise<T> {
48-
return await new Promise<T>((resolve, reject) => {
49-
const { id, handler } = task
50-
const run: TaskRun = () => {
51-
this._running++
52-
handler().then(
53-
result => {
54-
resolve(result)
55-
}
56-
).catch(
57-
() => {
58-
// eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors, prefer-promise-reject-errors -- ignore
59-
reject('failed')
60-
}
61-
).finally(() => {
62-
this._running--
63-
this._taskMap.delete(id)
64-
this._next()
65-
})
66-
}
25+
private readonly _callback: Nullable<TaskFinishedCallback>
6726

68-
const oldTaskWrapper = this._taskMap.get(id)
69-
if (isValid(oldTaskWrapper)) {
70-
oldTaskWrapper.reject('canceled')
27+
constructor (callback: TaskFinishedCallback) {
28+
this._callback = callback
29+
}
7130

72-
const index = this._queue.indexOf(oldTaskWrapper.run)
73-
if (index > -1) {
74-
this._queue.splice(index, 1)
31+
add (tasks: Record<string, Promise<unknown>>): void {
32+
if (!this._running) {
33+
void this._runTask(tasks)
34+
} else {
35+
if (isValid(this._holdingTasks)) {
36+
this._holdingTasks = {
37+
...this._holdingTasks,
38+
...tasks
7539
}
40+
} else {
41+
this._holdingTasks = tasks
7642
}
77-
78-
this._taskMap.set(id, { run, reject })
79-
this._queue.push(run)
80-
this._next()
81-
})
82-
}
83-
84-
private _next (): void {
85-
while (this._running < this._limit && this._queue.length > 0) {
86-
const fn = this._queue.shift()
87-
fn?.()
8843
}
8944
}
9045

91-
remove (id: string): void {
92-
const taskWrapper = this._taskMap.get(id)
93-
if (isValid(taskWrapper)) {
94-
this._taskMap.delete(id)
95-
96-
const index = this._queue.indexOf(taskWrapper.run)
97-
if (index > -1) {
98-
this._queue.splice(index, 1)
46+
private async _runTask (tasks: Record<string, Promise<unknown>>): Promise<void> {
47+
this._running = true
48+
try {
49+
await Promise.all(Object.values(tasks))
50+
} finally {
51+
this._running = false
52+
this._callback?.()
53+
if (isValid(this._holdingTasks)) {
54+
const next = this._holdingTasks
55+
void this._runTask(next)
56+
this._holdingTasks = null
9957
}
100-
101-
taskWrapper.reject('canceled')
10258
}
10359
}
10460

10561
clear (): void {
106-
for (const [, { reject }] of this._taskMap) {
107-
reject('canceled')
108-
}
109-
this._taskMap.clear()
110-
this._queue = []
62+
this._holdingTasks = null
11163
}
11264
}

src/component/Indicator.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,6 @@ export interface IndicatorOnDataStateChangeParams<D> {
111111

112112
indicator: Indicator<D>
113113
}
114-
export type IndicatorOnDataStateChangeCallback<D> = (params: IndicatorOnDataStateChangeParams<D>) => void
115114

116115
export interface Indicator<D = unknown, C = unknown, E = unknown> {
117116
/**
@@ -219,11 +218,6 @@ export interface Indicator<D = unknown, C = unknown, E = unknown> {
219218
*/
220219
draw: Nullable<IndicatorDrawCallback<D, C, E>>
221220

222-
/**
223-
* Data state change
224-
*/
225-
onDataStateChange: Nullable<IndicatorOnDataStateChangeCallback<D>>
226-
227221
/**
228222
* Calculation result
229223
*/
@@ -352,8 +346,6 @@ export default class IndicatorImp<D = unknown, C = unknown, E = unknown> impleme
352346
createTooltipDataSource: Nullable<IndicatorCreateTooltipDataSourceCallback<D>> = null
353347
draw: Nullable<IndicatorDrawCallback<D, C, E>> = null
354348

355-
onDataStateChange: Nullable<IndicatorOnDataStateChangeCallback<D>> = null
356-
357349
result: D[] = []
358350

359351
private _prevIndicator: Indicator<D, C, E>

0 commit comments

Comments
 (0)