@d-zero/dealer 1.6.5 → 1.7.0
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/README.md +30 -33
- package/dist/deal.d.ts +26 -24
- package/dist/deal.js +19 -24
- package/dist/dealer.d.ts +35 -35
- package/dist/dealer.js +43 -46
- package/dist/lanes.d.ts +18 -23
- package/dist/lanes.js +15 -17
- package/dist/types.d.ts +13 -7
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -38,6 +38,31 @@ await deal(
|
|
|
38
38
|
);
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
+
### キャンセル
|
|
42
|
+
|
|
43
|
+
`AbortSignal`を渡すことで、処理を途中で中断できます。実行中のワーカーは完了まで待機し、新しいワーカーの起動のみが停止されます。
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
const controller = new AbortController();
|
|
47
|
+
|
|
48
|
+
// 外部イベント(タイムアウトなど)でキャンセル
|
|
49
|
+
setTimeout(() => controller.abort(), 30_000);
|
|
50
|
+
|
|
51
|
+
await deal(
|
|
52
|
+
items,
|
|
53
|
+
(item, update, index) => {
|
|
54
|
+
return async () => {
|
|
55
|
+
update(`Processing item ${index}...`);
|
|
56
|
+
await item.process();
|
|
57
|
+
};
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
limit: 10,
|
|
61
|
+
signal: controller.signal,
|
|
62
|
+
},
|
|
63
|
+
);
|
|
64
|
+
```
|
|
65
|
+
|
|
41
66
|
### deal関数
|
|
42
67
|
|
|
43
68
|
コレクションを並列処理し、ログを順次出力します。
|
|
@@ -80,23 +105,6 @@ async function deal<T extends WeakKey>(
|
|
|
80
105
|
- これはアイテム開始**後**、最初の出力の**前**に発生
|
|
81
106
|
- 実際の処理が始まる(ユーザーコードからの最初の `update()` 呼び出し)
|
|
82
107
|
|
|
83
|
-
#### エラーハンドリング
|
|
84
|
-
|
|
85
|
-
ワーカー(`start()`関数)がエラーを投げた場合、残りのワーカーの処理は継続されます。すべてのワーカーが完了(成功または失敗)した後、1つ以上のエラーがあれば`AggregateError`でrejectされます。
|
|
86
|
-
|
|
87
|
-
```ts
|
|
88
|
-
try {
|
|
89
|
-
await deal(items, setup, options);
|
|
90
|
-
} catch (error) {
|
|
91
|
-
if (error instanceof AggregateError) {
|
|
92
|
-
console.error(`${error.errors.length} workers failed:`);
|
|
93
|
-
for (const e of error.errors) {
|
|
94
|
-
console.error(e);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
```
|
|
99
|
-
|
|
100
108
|
### DealOptions型
|
|
101
109
|
|
|
102
110
|
```ts
|
|
@@ -112,13 +120,14 @@ type DealOptions<T = unknown> = DealerOptions<T> &
|
|
|
112
120
|
|
|
113
121
|
- `limit?: number`: 同時実行数の制限(デフォルト: 10)
|
|
114
122
|
- `onPush?: (item: T) => boolean`: `push()`時のフィルタ関数。`false`を返すとそのアイテムは拒否される(例: 重複排除)
|
|
123
|
+
- `signal?: AbortSignal`: 処理のキャンセルに使用する`AbortSignal`。シグナルがabortされると新しいワーカーの起動を停止し、実行中のワーカーの完了を待ってから終了する
|
|
115
124
|
- `header?: DealHeader`: 進捗ヘッダーを生成する関数
|
|
116
125
|
- `debug?: boolean`: デバッグログを表示するかどうか
|
|
117
126
|
- `interval?: number | DelayOptions`: 各処理の間隔(ミリ秒またはDelayOptions)
|
|
118
127
|
- `animations?: Animations`: アニメーション定義
|
|
119
128
|
- `fps?: FPS`: フレームレート(12, 24, 30, 60)
|
|
120
129
|
- `indent?: string`: ログのインデント文字列
|
|
121
|
-
- `sort?: (a:
|
|
130
|
+
- `sort?: (a: [number, string], b: [number, string]) => number`: ログのソート関数
|
|
122
131
|
- `verbose?: boolean`: 詳細ログモード
|
|
123
132
|
|
|
124
133
|
### DealHeader型
|
|
@@ -137,7 +146,7 @@ type DealHeader = (
|
|
|
137
146
|
#### パラメータ
|
|
138
147
|
|
|
139
148
|
- `progress`: 進捗率(0〜1)
|
|
140
|
-
- `done`:
|
|
149
|
+
- `done`: 完了したアイテム数
|
|
141
150
|
- `total`: 総アイテム数
|
|
142
151
|
- `limit`: 同時実行数制限
|
|
143
152
|
|
|
@@ -158,19 +167,7 @@ constructor(items: readonly T[], options?: DealerOptions<T>)
|
|
|
158
167
|
- `items`: 処理対象のアイテム
|
|
159
168
|
- `options.limit`: 同時実行数の制限(デフォルト: 10)
|
|
160
169
|
- `options.onPush`: `push()`時のフィルタ関数
|
|
161
|
-
|
|
162
|
-
#### プロパティ
|
|
163
|
-
|
|
164
|
-
##### get errors(): ReadonlyArray<{ item: T; error: unknown }>
|
|
165
|
-
|
|
166
|
-
ワーカーの実行中に発生したエラーの一覧を返します。各エントリにはエラーを起こしたアイテムとエラーオブジェクトが含まれます。
|
|
167
|
-
|
|
168
|
-
```ts
|
|
169
|
-
await runDealer(dealer);
|
|
170
|
-
for (const { item, error } of dealer.errors) {
|
|
171
|
-
console.error('Failed item:', item, error);
|
|
172
|
-
}
|
|
173
|
-
```
|
|
170
|
+
- `options.signal`: 処理のキャンセルに使用する`AbortSignal`
|
|
174
171
|
|
|
175
172
|
#### メソッド
|
|
176
173
|
|
|
@@ -214,7 +211,7 @@ dealer.progress((progress, done, total, limit) => {
|
|
|
214
211
|
|
|
215
212
|
##### async push(...items: T[])
|
|
216
213
|
|
|
217
|
-
実行中にアイテムをキューに追加します。追加されたアイテムには`setup()
|
|
214
|
+
実行中にアイテムをキューに追加します。追加されたアイテムには`setup()`で設定した初期化関数が自動適用されます。処理完了後または`signal`がabort済みの場合、呼び出しは無視されます。
|
|
218
215
|
|
|
219
216
|
```ts
|
|
220
217
|
await dealer.push(newItem1, newItem2);
|
package/dist/deal.d.ts
CHANGED
|
@@ -2,26 +2,24 @@ import type { DealerOptions } from './dealer.js';
|
|
|
2
2
|
import type { LanesOptions } from './lanes.js';
|
|
3
3
|
import type { DelayOptions } from '@d-zero/shared/delay';
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* @template T -
|
|
5
|
+
* {@link deal} 関数のオプション。
|
|
6
|
+
* {@link DealerOptions} と {@link LanesOptions} を合成し、
|
|
7
|
+
* ヘッダー・デバッグ・インターバルの設定を追加したもの。
|
|
8
|
+
* @template T - 処理対象アイテムの型
|
|
9
9
|
*/
|
|
10
10
|
export type DealOptions<T = unknown> = DealerOptions<T> & LanesOptions & {
|
|
11
|
-
/** Function to generate the progress header string */
|
|
12
11
|
readonly header?: DealHeader;
|
|
13
|
-
/** Whether to display debug log output */
|
|
14
12
|
readonly debug?: boolean;
|
|
15
|
-
/** Delay between each worker start, in milliseconds or as a DelayOptions object */
|
|
16
13
|
readonly interval?: number | DelayOptions;
|
|
17
14
|
};
|
|
18
15
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* @param
|
|
22
|
-
* @param
|
|
23
|
-
* @param
|
|
24
|
-
* @
|
|
16
|
+
* 進捗情報をヘッダー文字列に変換するコールバック型。
|
|
17
|
+
* 返却文字列にはアニメーション変数(`%earth%`, `%dots%` など)を含めることができる。
|
|
18
|
+
* @param progress - 進捗率(0〜1)
|
|
19
|
+
* @param done - 完了したアイテム数
|
|
20
|
+
* @param total - 総アイテム数
|
|
21
|
+
* @param limit - 同時実行数制限
|
|
22
|
+
* @returns ヘッダーとして表示する文字列
|
|
25
23
|
*/
|
|
26
24
|
export type DealHeader = (progress: number, done: number, total: number, limit: number) => string;
|
|
27
25
|
/**
|
|
@@ -53,16 +51,20 @@ export type DealHeader = (progress: number, done: number, total: number, limit:
|
|
|
53
51
|
* - All wait logs (including interval delay) are output via `delay()` callback
|
|
54
52
|
* - This ensures the determined interval (even for random delays) is used for countdown
|
|
55
53
|
* - The `%countdown()` function displays remaining time based on the actual delay duration
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
54
|
+
*
|
|
55
|
+
* ### Cancellation via AbortSignal
|
|
56
|
+
* - Pass `signal` option with an `AbortSignal` to enable cancellation
|
|
57
|
+
* - When the signal is aborted:
|
|
58
|
+
* 1. No new workers will be launched
|
|
59
|
+
* 2. Currently running workers will continue until they complete
|
|
60
|
+
* 3. `push()` calls after abort are silently ignored
|
|
61
|
+
* 4. The returned Promise resolves after all running workers finish
|
|
62
|
+
* - If the signal is already aborted before `play()`, the Promise resolves immediately
|
|
63
|
+
* without processing any items
|
|
64
|
+
* @template T - 処理対象アイテムの型(WeakKey 制約)
|
|
65
|
+
* @param items - 処理対象のアイテムのコレクション
|
|
66
|
+
* @param setup - 各アイテムを初期化し、開始関数を返すコールバック
|
|
67
|
+
* @param options - 並列処理・ログ出力・インターバルの設定オプション
|
|
68
|
+
* @returns 全アイテムの処理完了またはキャンセル完了時に解決する Promise
|
|
67
69
|
*/
|
|
68
70
|
export declare function deal<T extends WeakKey>(items: readonly T[], setup: (process: T, update: (log: string) => void, index: number, setLineHeader: (lineHeader: string) => void, push: (...items: T[]) => Promise<void>) => Promise<() => void | Promise<void>> | (() => void | Promise<void>), options?: DealOptions<T>): Promise<void>;
|
package/dist/deal.js
CHANGED
|
@@ -31,17 +31,21 @@ const DEBUG_ID = Number.MIN_SAFE_INTEGER;
|
|
|
31
31
|
* - All wait logs (including interval delay) are output via `delay()` callback
|
|
32
32
|
* - This ensures the determined interval (even for random delays) is used for countdown
|
|
33
33
|
* - The `%countdown()` function displays remaining time based on the actual delay duration
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
34
|
+
*
|
|
35
|
+
* ### Cancellation via AbortSignal
|
|
36
|
+
* - Pass `signal` option with an `AbortSignal` to enable cancellation
|
|
37
|
+
* - When the signal is aborted:
|
|
38
|
+
* 1. No new workers will be launched
|
|
39
|
+
* 2. Currently running workers will continue until they complete
|
|
40
|
+
* 3. `push()` calls after abort are silently ignored
|
|
41
|
+
* 4. The returned Promise resolves after all running workers finish
|
|
42
|
+
* - If the signal is already aborted before `play()`, the Promise resolves immediately
|
|
43
|
+
* without processing any items
|
|
44
|
+
* @template T - 処理対象アイテムの型(WeakKey 制約)
|
|
45
|
+
* @param items - 処理対象のアイテムのコレクション
|
|
46
|
+
* @param setup - 各アイテムを初期化し、開始関数を返すコールバック
|
|
47
|
+
* @param options - 並列処理・ログ出力・インターバルの設定オプション
|
|
48
|
+
* @returns 全アイテムの処理完了またはキャンセル完了時に解決する Promise
|
|
45
49
|
*/
|
|
46
50
|
export async function deal(items, setup, options) {
|
|
47
51
|
const dealer = new Dealer(items, options);
|
|
@@ -63,12 +67,8 @@ export async function deal(items, setup, options) {
|
|
|
63
67
|
await delay(options?.interval ?? 0, (determinedInterval) => {
|
|
64
68
|
update(`Waiting interval: %countdown(${determinedInterval},${index}_interval)%ms`);
|
|
65
69
|
});
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
finally {
|
|
70
|
-
lanes.delete(index);
|
|
71
|
-
}
|
|
70
|
+
await start();
|
|
71
|
+
lanes.delete(index);
|
|
72
72
|
};
|
|
73
73
|
});
|
|
74
74
|
if (options?.debug) {
|
|
@@ -76,15 +76,10 @@ export async function deal(items, setup, options) {
|
|
|
76
76
|
lanes.update(DEBUG_ID, `[DEBUG]: ${log}`);
|
|
77
77
|
});
|
|
78
78
|
}
|
|
79
|
-
return new Promise((resolve
|
|
79
|
+
return new Promise((resolve) => {
|
|
80
80
|
dealer.finish(() => {
|
|
81
81
|
lanes.close();
|
|
82
|
-
|
|
83
|
-
reject(new AggregateError(dealer.errors.map((e) => e.error), `${dealer.errors.length} worker(s) failed`));
|
|
84
|
-
}
|
|
85
|
-
else {
|
|
86
|
-
resolve();
|
|
87
|
-
}
|
|
82
|
+
resolve();
|
|
88
83
|
});
|
|
89
84
|
dealer.play();
|
|
90
85
|
});
|
package/dist/dealer.d.ts
CHANGED
|
@@ -1,67 +1,67 @@
|
|
|
1
1
|
import type { ProcessInitializer } from './types.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
* @template T -
|
|
3
|
+
* {@link Dealer} のコンストラクタオプション。
|
|
4
|
+
* @template T - 処理対象アイテムの型
|
|
5
5
|
*/
|
|
6
6
|
export interface DealerOptions<T = unknown> {
|
|
7
|
-
/**
|
|
7
|
+
/** 同時実行ワーカー数の上限。デフォルトは `10`。 */
|
|
8
8
|
limit?: number;
|
|
9
|
-
/**
|
|
9
|
+
/**
|
|
10
|
+
* {@link Dealer.push} 時に呼ばれるフィルタ関数。
|
|
11
|
+
* `false` を返すとそのアイテムはキューに追加されない。
|
|
12
|
+
* @param item - push されたアイテム
|
|
13
|
+
* @returns アイテムを受け入れる場合は `true`
|
|
14
|
+
*/
|
|
10
15
|
onPush?: (item: T) => boolean;
|
|
16
|
+
/**
|
|
17
|
+
* 処理のキャンセルに使用する `AbortSignal`。
|
|
18
|
+
* シグナルが abort されると新しいワーカーの起動を停止し、
|
|
19
|
+
* 実行中のワーカーの完了を待ってから終了する。
|
|
20
|
+
*/
|
|
21
|
+
signal?: AbortSignal;
|
|
11
22
|
}
|
|
12
23
|
/**
|
|
13
|
-
*
|
|
24
|
+
* アイテムを並列処理するワーカープールマネージャー。
|
|
14
25
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* @template T - The type of items to process, must extend WeakKey
|
|
26
|
+
* 典型的な使用順序: {@link setup} → {@link finish} / {@link progress} → {@link play}。
|
|
27
|
+
* 処理中に {@link push} で動的にアイテムを追加できる。
|
|
28
|
+
* @template T - 処理対象アイテムの型(WeakKey 制約)
|
|
19
29
|
*/
|
|
20
30
|
export declare class Dealer<T extends WeakKey> {
|
|
21
31
|
#private;
|
|
22
|
-
/**
|
|
23
|
-
* Errors collected from failed workers during processing.
|
|
24
|
-
* @returns Array of objects containing the failed item and its error
|
|
25
|
-
*/
|
|
26
|
-
get errors(): ReadonlyArray<{
|
|
27
|
-
item: T;
|
|
28
|
-
error: unknown;
|
|
29
|
-
}>;
|
|
30
|
-
/**
|
|
31
|
-
* @param items - Collection of items to process
|
|
32
|
-
* @param options - Configuration options
|
|
33
|
-
*/
|
|
34
32
|
constructor(items: readonly T[], options?: DealerOptions<T>);
|
|
35
33
|
/**
|
|
36
|
-
*
|
|
37
|
-
* @param listener -
|
|
34
|
+
* デバッグログのリスナーを設定する。
|
|
35
|
+
* @param listener - デバッグメッセージを受け取るコールバック
|
|
38
36
|
*/
|
|
39
37
|
debug(listener: (log: string) => void): void;
|
|
40
38
|
/**
|
|
41
|
-
*
|
|
42
|
-
* @param listener -
|
|
39
|
+
* 全アイテムの処理完了(またはキャンセル完了)時に呼ばれるリスナーを設定する。
|
|
40
|
+
* @param listener - 完了時に呼ばれるコールバック
|
|
43
41
|
*/
|
|
44
42
|
finish(listener: () => void): void;
|
|
45
43
|
/**
|
|
46
|
-
*
|
|
44
|
+
* 並列処理を開始する。
|
|
45
|
+
* {@link setup} を先に呼び出す必要がある。
|
|
47
46
|
*/
|
|
48
47
|
play(): void;
|
|
49
48
|
/**
|
|
50
|
-
*
|
|
51
|
-
*
|
|
49
|
+
* 進捗更新のリスナーを設定する。
|
|
50
|
+
* アイテムが完了するたびに呼び出される。
|
|
51
|
+
* @param listener - 進捗情報を受け取るコールバック
|
|
52
52
|
*/
|
|
53
53
|
progress(listener: (progress: number, done: number, total: number, limit: number) => void): void;
|
|
54
54
|
/**
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* @param items -
|
|
55
|
+
* 実行中にアイテムをキューに追加する。
|
|
56
|
+
* 追加されたアイテムには {@link setup} で設定した初期化関数が自動適用される。
|
|
57
|
+
* 処理完了後または signal が abort 済みの場合、呼び出しは無視される。
|
|
58
|
+
* @param items - 追加するアイテム
|
|
59
59
|
*/
|
|
60
60
|
push(...items: T[]): Promise<void>;
|
|
61
61
|
/**
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
* @param initializer -
|
|
62
|
+
* 各アイテムの初期化関数を設定する。
|
|
63
|
+
* {@link play} を呼ぶ前に必ず呼び出すこと。
|
|
64
|
+
* @param initializer - 各アイテムを初期化し、実行関数を返すコールバック
|
|
65
65
|
*/
|
|
66
66
|
setup(initializer: ProcessInitializer<T>): Promise<void>;
|
|
67
67
|
}
|
package/dist/dealer.js
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* アイテムを並列処理するワーカープールマネージャー。
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* @template T - The type of items to process, must extend WeakKey
|
|
4
|
+
* 典型的な使用順序: {@link setup} → {@link finish} / {@link progress} → {@link play}。
|
|
5
|
+
* 処理中に {@link push} で動的にアイテムを追加できる。
|
|
6
|
+
* @template T - 処理対象アイテムの型(WeakKey 制約)
|
|
8
7
|
*/
|
|
9
8
|
export class Dealer {
|
|
10
9
|
#debug = () => { };
|
|
11
10
|
#done = new WeakSet();
|
|
12
11
|
#doneCount = 0;
|
|
13
|
-
#errors = [];
|
|
14
12
|
#finish = () => { };
|
|
15
13
|
#finished = false;
|
|
16
14
|
#initializer = null;
|
|
@@ -20,59 +18,52 @@ export class Dealer {
|
|
|
20
18
|
#onPush;
|
|
21
19
|
#pendingInitCount = 0;
|
|
22
20
|
#progress = () => { };
|
|
21
|
+
#signal;
|
|
23
22
|
#starts = new WeakMap();
|
|
24
23
|
#workers = new Set();
|
|
25
|
-
/**
|
|
26
|
-
* Errors collected from failed workers during processing.
|
|
27
|
-
* @returns Array of objects containing the failed item and its error
|
|
28
|
-
*/
|
|
29
|
-
get errors() {
|
|
30
|
-
return this.#errors;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* @param items - Collection of items to process
|
|
34
|
-
* @param options - Configuration options
|
|
35
|
-
*/
|
|
36
24
|
constructor(items, options) {
|
|
37
25
|
this.#items = [...items];
|
|
38
26
|
this.#limit = options?.limit ?? 10;
|
|
39
27
|
this.#onPush = options?.onPush;
|
|
28
|
+
this.#signal = options?.signal;
|
|
40
29
|
}
|
|
41
30
|
/**
|
|
42
|
-
*
|
|
43
|
-
* @param listener -
|
|
31
|
+
* デバッグログのリスナーを設定する。
|
|
32
|
+
* @param listener - デバッグメッセージを受け取るコールバック
|
|
44
33
|
*/
|
|
45
34
|
debug(listener) {
|
|
46
35
|
this.#debug = listener;
|
|
47
36
|
}
|
|
48
37
|
/**
|
|
49
|
-
*
|
|
50
|
-
* @param listener -
|
|
38
|
+
* 全アイテムの処理完了(またはキャンセル完了)時に呼ばれるリスナーを設定する。
|
|
39
|
+
* @param listener - 完了時に呼ばれるコールバック
|
|
51
40
|
*/
|
|
52
41
|
finish(listener) {
|
|
53
42
|
this.#finish = listener;
|
|
54
43
|
}
|
|
55
44
|
/**
|
|
56
|
-
*
|
|
45
|
+
* 並列処理を開始する。
|
|
46
|
+
* {@link setup} を先に呼び出す必要がある。
|
|
57
47
|
*/
|
|
58
48
|
play() {
|
|
59
49
|
this.#deal();
|
|
60
50
|
}
|
|
61
51
|
/**
|
|
62
|
-
*
|
|
63
|
-
*
|
|
52
|
+
* 進捗更新のリスナーを設定する。
|
|
53
|
+
* アイテムが完了するたびに呼び出される。
|
|
54
|
+
* @param listener - 進捗情報を受け取るコールバック
|
|
64
55
|
*/
|
|
65
56
|
progress(listener) {
|
|
66
57
|
this.#progress = listener;
|
|
67
58
|
}
|
|
68
59
|
/**
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
* @param items -
|
|
60
|
+
* 実行中にアイテムをキューに追加する。
|
|
61
|
+
* 追加されたアイテムには {@link setup} で設定した初期化関数が自動適用される。
|
|
62
|
+
* 処理完了後または signal が abort 済みの場合、呼び出しは無視される。
|
|
63
|
+
* @param items - 追加するアイテム
|
|
73
64
|
*/
|
|
74
65
|
async push(...items) {
|
|
75
|
-
if (this.#finished) {
|
|
66
|
+
if (this.#finished || this.#signal?.aborted) {
|
|
76
67
|
return;
|
|
77
68
|
}
|
|
78
69
|
for (const item of items) {
|
|
@@ -84,9 +75,9 @@ export class Dealer {
|
|
|
84
75
|
}
|
|
85
76
|
}
|
|
86
77
|
/**
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
* @param initializer -
|
|
78
|
+
* 各アイテムの初期化関数を設定する。
|
|
79
|
+
* {@link play} を呼ぶ前に必ず呼び出すこと。
|
|
80
|
+
* @param initializer - 各アイテムを初期化し、実行関数を返すコールバック
|
|
90
81
|
*/
|
|
91
82
|
async setup(initializer) {
|
|
92
83
|
this.#initializer = initializer;
|
|
@@ -97,13 +88,10 @@ export class Dealer {
|
|
|
97
88
|
const total = this.#items.length;
|
|
98
89
|
this.#progress(total === 0 ? 0 : this.#doneCount / total, this.#doneCount, total, this.#limit);
|
|
99
90
|
}
|
|
100
|
-
#completeWorker(worker) {
|
|
101
|
-
this.#workers.delete(worker);
|
|
102
|
-
this.#done.add(worker);
|
|
103
|
-
this.#doneCount++;
|
|
104
|
-
this.#deal();
|
|
105
|
-
}
|
|
106
91
|
#deal() {
|
|
92
|
+
if (this.#finished) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
107
95
|
const total = this.#items.length;
|
|
108
96
|
this.#debug(`Done: ${this.#doneCount}/${total} (Limit: ${this.#limit})`);
|
|
109
97
|
this.#progress(total === 0 ? 0 : this.#doneCount / total, this.#doneCount, total, this.#limit);
|
|
@@ -112,6 +100,13 @@ export class Dealer {
|
|
|
112
100
|
this.#finish();
|
|
113
101
|
return;
|
|
114
102
|
}
|
|
103
|
+
if (this.#signal?.aborted) {
|
|
104
|
+
if (this.#workers.size === 0) {
|
|
105
|
+
this.#finished = true;
|
|
106
|
+
this.#finish();
|
|
107
|
+
}
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
115
110
|
while (this.#workers.size < this.#limit) {
|
|
116
111
|
const worker = this.#draw();
|
|
117
112
|
if (!worker) {
|
|
@@ -122,13 +117,11 @@ export class Dealer {
|
|
|
122
117
|
if (!start) {
|
|
123
118
|
throw new Error(`Didn't have a starting function`);
|
|
124
119
|
}
|
|
125
|
-
void start()
|
|
126
|
-
.
|
|
127
|
-
this.#
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
this.#errors.push({ item: worker, error });
|
|
131
|
-
this.#completeWorker(worker);
|
|
120
|
+
void start().then(() => {
|
|
121
|
+
this.#workers.delete(worker);
|
|
122
|
+
this.#done.add(worker);
|
|
123
|
+
this.#doneCount++;
|
|
124
|
+
this.#deal();
|
|
132
125
|
});
|
|
133
126
|
}
|
|
134
127
|
}
|
|
@@ -149,9 +142,13 @@ export class Dealer {
|
|
|
149
142
|
throw new Error('setup() must be called before push()');
|
|
150
143
|
}
|
|
151
144
|
const start = await this.#initializer(item, this.#nextIndex++);
|
|
145
|
+
this.#pendingInitCount--;
|
|
146
|
+
if (this.#signal?.aborted) {
|
|
147
|
+
this.#deal();
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
152
150
|
this.#starts.set(item, async () => await start());
|
|
153
151
|
this.#items.push(item);
|
|
154
|
-
this.#pendingInitCount--;
|
|
155
152
|
this.#deal();
|
|
156
153
|
}
|
|
157
154
|
}
|
package/dist/lanes.d.ts
CHANGED
|
@@ -1,60 +1,55 @@
|
|
|
1
1
|
import type { Animations, FPS } from './types.js';
|
|
2
2
|
type Log = readonly [id: number, message: string];
|
|
3
3
|
type SortFunc = (a: Log, b: Log) => number;
|
|
4
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* {@link Lanes} のコンストラクタオプション。
|
|
6
|
+
*/
|
|
5
7
|
export type LanesOptions = {
|
|
6
|
-
/** Custom animation definitions to override or extend built-in presets */
|
|
7
8
|
readonly animations?: Animations;
|
|
8
|
-
/** Frame rate for display rendering */
|
|
9
9
|
readonly fps?: FPS;
|
|
10
|
-
/** Indent string prepended to each log line */
|
|
11
10
|
readonly indent?: string;
|
|
12
|
-
/** Sort function for ordering log entries by their ID */
|
|
13
11
|
readonly sort?: SortFunc;
|
|
14
|
-
/** When true, logs are appended line-by-line to stdout instead of being redrawn in-place */
|
|
15
12
|
readonly verbose?: boolean;
|
|
16
13
|
};
|
|
17
14
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
15
|
+
* 複数のログラインを管理し、順序付きでターミナルに表示するクラス。
|
|
16
|
+
* verbose モードでは上書き表示ではなく追記出力を行う。
|
|
20
17
|
*/
|
|
21
18
|
export declare class Lanes {
|
|
22
19
|
#private;
|
|
23
|
-
/**
|
|
24
|
-
* @param options - Display configuration options
|
|
25
|
-
*/
|
|
26
20
|
constructor(options?: LanesOptions);
|
|
27
21
|
/**
|
|
28
|
-
*
|
|
29
|
-
* @param options -
|
|
22
|
+
* すべてのログをクリアする。verbose モードでは何もしない。
|
|
23
|
+
* @param options - クリアオプション
|
|
30
24
|
* @param options.header
|
|
31
25
|
*/
|
|
32
26
|
clear(options?: {
|
|
33
27
|
header?: boolean;
|
|
34
28
|
}): void;
|
|
35
29
|
/**
|
|
36
|
-
*
|
|
30
|
+
* ディスプレイを閉じ、リソースを解放する。
|
|
37
31
|
*/
|
|
38
32
|
close(): void;
|
|
39
33
|
/**
|
|
40
|
-
*
|
|
41
|
-
* @param id -
|
|
34
|
+
* 指定した ID のログを削除する。verbose モードでは何もしない。
|
|
35
|
+
* @param id - 削除するログの ID
|
|
42
36
|
*/
|
|
43
37
|
delete(id: number): void;
|
|
44
38
|
/**
|
|
45
|
-
*
|
|
46
|
-
* @param text -
|
|
39
|
+
* ヘッダーテキストを設定する。
|
|
40
|
+
* @param text - ヘッダーとして表示する文字列
|
|
47
41
|
*/
|
|
48
42
|
header(text: string): void;
|
|
49
43
|
/**
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* @param
|
|
44
|
+
* 指定した ID のログを更新する。
|
|
45
|
+
* verbose モードではヘッダーとログを連結して即時出力する。
|
|
46
|
+
* @param id - 更新するログの ID
|
|
47
|
+
* @param log - ログメッセージ
|
|
53
48
|
*/
|
|
54
49
|
update(id: number, log: string): void;
|
|
55
50
|
/**
|
|
56
|
-
*
|
|
57
|
-
*
|
|
51
|
+
* 現在のログをソートしてターミナルに表示する。
|
|
52
|
+
* verbose モードでは何もしない。
|
|
58
53
|
*/
|
|
59
54
|
write(): void;
|
|
60
55
|
}
|
package/dist/lanes.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Display } from './display.js';
|
|
2
2
|
const RESET = '\u001B[0m';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* 複数のログラインを管理し、順序付きでターミナルに表示するクラス。
|
|
5
|
+
* verbose モードでは上書き表示ではなく追記出力を行う。
|
|
6
6
|
*/
|
|
7
7
|
export class Lanes {
|
|
8
8
|
#display;
|
|
@@ -11,9 +11,6 @@ export class Lanes {
|
|
|
11
11
|
#logs = new Map();
|
|
12
12
|
#sort = ([a], [b]) => a - b;
|
|
13
13
|
#verbose;
|
|
14
|
-
/**
|
|
15
|
-
* @param options - Display configuration options
|
|
16
|
-
*/
|
|
17
14
|
constructor(options) {
|
|
18
15
|
this.#display = new Display({
|
|
19
16
|
animations: options?.animations,
|
|
@@ -25,8 +22,8 @@ export class Lanes {
|
|
|
25
22
|
this.#verbose = options?.verbose ?? false;
|
|
26
23
|
}
|
|
27
24
|
/**
|
|
28
|
-
*
|
|
29
|
-
* @param options -
|
|
25
|
+
* すべてのログをクリアする。verbose モードでは何もしない。
|
|
26
|
+
* @param options - クリアオプション
|
|
30
27
|
* @param options.header
|
|
31
28
|
*/
|
|
32
29
|
clear(options) {
|
|
@@ -40,14 +37,14 @@ export class Lanes {
|
|
|
40
37
|
this.write();
|
|
41
38
|
}
|
|
42
39
|
/**
|
|
43
|
-
*
|
|
40
|
+
* ディスプレイを閉じ、リソースを解放する。
|
|
44
41
|
*/
|
|
45
42
|
close() {
|
|
46
43
|
this.#display.close();
|
|
47
44
|
}
|
|
48
45
|
/**
|
|
49
|
-
*
|
|
50
|
-
* @param id -
|
|
46
|
+
* 指定した ID のログを削除する。verbose モードでは何もしない。
|
|
47
|
+
* @param id - 削除するログの ID
|
|
51
48
|
*/
|
|
52
49
|
delete(id) {
|
|
53
50
|
if (this.#verbose) {
|
|
@@ -57,8 +54,8 @@ export class Lanes {
|
|
|
57
54
|
this.write();
|
|
58
55
|
}
|
|
59
56
|
/**
|
|
60
|
-
*
|
|
61
|
-
* @param text -
|
|
57
|
+
* ヘッダーテキストを設定する。
|
|
58
|
+
* @param text - ヘッダーとして表示する文字列
|
|
62
59
|
*/
|
|
63
60
|
header(text) {
|
|
64
61
|
this.#header = text;
|
|
@@ -68,9 +65,10 @@ export class Lanes {
|
|
|
68
65
|
this.write();
|
|
69
66
|
}
|
|
70
67
|
/**
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
* @param
|
|
68
|
+
* 指定した ID のログを更新する。
|
|
69
|
+
* verbose モードではヘッダーとログを連結して即時出力する。
|
|
70
|
+
* @param id - 更新するログの ID
|
|
71
|
+
* @param log - ログメッセージ
|
|
74
72
|
*/
|
|
75
73
|
update(id, log) {
|
|
76
74
|
if (this.#verbose) {
|
|
@@ -81,8 +79,8 @@ export class Lanes {
|
|
|
81
79
|
this.write();
|
|
82
80
|
}
|
|
83
81
|
/**
|
|
84
|
-
*
|
|
85
|
-
*
|
|
82
|
+
* 現在のログをソートしてターミナルに表示する。
|
|
83
|
+
* verbose モードでは何もしない。
|
|
86
84
|
*/
|
|
87
85
|
write() {
|
|
88
86
|
if (this.#verbose) {
|
package/dist/types.d.ts
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* アニメーション定義のマップ。
|
|
3
|
+
* キーはアニメーション名(`%name%` 形式でログ中に埋め込み可能)、
|
|
4
|
+
* 値は先頭が FPS、残りがスプライトフレームのタプル。
|
|
5
|
+
*/
|
|
2
6
|
export type Animations = Record<string, [fps: number, ...sprites: string[]]>;
|
|
3
|
-
/**
|
|
7
|
+
/**
|
|
8
|
+
* サポートされるフレームレート。
|
|
9
|
+
*/
|
|
4
10
|
export type FPS = 12 | 24 | 30 | 60;
|
|
5
11
|
/**
|
|
6
|
-
*
|
|
7
|
-
* @template T -
|
|
8
|
-
* @param process -
|
|
9
|
-
* @param index -
|
|
10
|
-
* @returns
|
|
12
|
+
* 各アイテムを初期化し、実行関数を返すコールバック。
|
|
13
|
+
* @template T - 処理対象アイテムの型
|
|
14
|
+
* @param process - 初期化対象のアイテム
|
|
15
|
+
* @param index - アイテムのインデックス(0始まり)
|
|
16
|
+
* @returns 処理を開始する関数を返す Promise
|
|
11
17
|
*/
|
|
12
18
|
export interface ProcessInitializer<T> {
|
|
13
19
|
(process: T, index: number): Promise<() => Promise<void> | void>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@d-zero/dealer",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "A tool that provides an API and CLI for parallel processing of collections and sequential logging to standard output",
|
|
5
5
|
"author": "D-ZERO",
|
|
6
6
|
"license": "MIT",
|
|
@@ -26,5 +26,5 @@
|
|
|
26
26
|
"@d-zero/shared": "0.20.1",
|
|
27
27
|
"ansi-colors": "4.1.3"
|
|
28
28
|
},
|
|
29
|
-
"gitHead": "
|
|
29
|
+
"gitHead": "866364294ddacc3095f65a9f8b488d40c4ccb904"
|
|
30
30
|
}
|