@hkdigital/lib-core 0.4.26 → 0.4.27
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/dist/network/loaders/audio/AudioScene.svelte.d.ts +11 -0
- package/dist/network/loaders/audio/AudioScene.svelte.js +65 -1
- package/dist/network/loaders/image/ImageScene.svelte.d.ts +11 -0
- package/dist/network/loaders/image/ImageScene.svelte.js +63 -1
- package/dist/network/states/NetworkLoader.svelte.d.ts +2 -2
- package/dist/network/states/NetworkLoader.svelte.js +15 -13
- package/dist/state/machines/loading-state-machine/LoadingStateMachine.svelte.d.ts +4 -4
- package/dist/state/machines/loading-state-machine/LoadingStateMachine.svelte.js +15 -9
- package/dist/state/machines/loading-state-machine/README.md +70 -45
- package/dist/state/machines/loading-state-machine/constants.d.ts +4 -2
- package/dist/state/machines/loading-state-machine/constants.js +4 -2
- package/package.json +1 -1
|
@@ -22,10 +22,21 @@ export default class AudioScene {
|
|
|
22
22
|
sourcesLoaded: number;
|
|
23
23
|
numberOfSources: number;
|
|
24
24
|
};
|
|
25
|
+
/**
|
|
26
|
+
* Get audio scene abort progress
|
|
27
|
+
*/
|
|
28
|
+
get abortProgress(): {
|
|
29
|
+
sourcesAborted: number;
|
|
30
|
+
numberOfSources: number;
|
|
31
|
+
};
|
|
25
32
|
/**
|
|
26
33
|
* Start loading all audio sources
|
|
27
34
|
*/
|
|
28
35
|
load(): void;
|
|
36
|
+
/**
|
|
37
|
+
* Abort loading all audio sources
|
|
38
|
+
*/
|
|
39
|
+
abort(): void;
|
|
29
40
|
destroy(): void;
|
|
30
41
|
/**
|
|
31
42
|
* Add in-memory audio source
|
|
@@ -6,8 +6,13 @@ import {
|
|
|
6
6
|
STATE_INITIAL,
|
|
7
7
|
STATE_LOADING,
|
|
8
8
|
STATE_LOADED,
|
|
9
|
+
STATE_ABORTING,
|
|
10
|
+
STATE_ABORTED,
|
|
11
|
+
STATE_ERROR,
|
|
9
12
|
LOAD,
|
|
10
|
-
LOADED
|
|
13
|
+
LOADED,
|
|
14
|
+
ABORT,
|
|
15
|
+
ABORTED
|
|
11
16
|
} from '../../../state/machines.js';
|
|
12
17
|
|
|
13
18
|
import AudioLoader from './AudioLoader.svelte.js';
|
|
@@ -83,6 +88,27 @@ export default class AudioScene {
|
|
|
83
88
|
};
|
|
84
89
|
});
|
|
85
90
|
|
|
91
|
+
#abortProgress = $derived.by(() => {
|
|
92
|
+
let sourcesAborted = 0;
|
|
93
|
+
const sources = this.#memorySources;
|
|
94
|
+
const numberOfSources = sources.length;
|
|
95
|
+
|
|
96
|
+
for (let j = 0; j < numberOfSources; j++) {
|
|
97
|
+
const source = sources[j];
|
|
98
|
+
const { audioLoader } = source;
|
|
99
|
+
const loaderState = audioLoader.state;
|
|
100
|
+
|
|
101
|
+
if (loaderState === STATE_ABORTED || loaderState === STATE_ERROR) {
|
|
102
|
+
sourcesAborted++;
|
|
103
|
+
}
|
|
104
|
+
} // end for
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
sourcesAborted,
|
|
108
|
+
numberOfSources
|
|
109
|
+
};
|
|
110
|
+
});
|
|
111
|
+
|
|
86
112
|
/**
|
|
87
113
|
* Construct AudioScene
|
|
88
114
|
*/
|
|
@@ -105,6 +131,17 @@ export default class AudioScene {
|
|
|
105
131
|
}
|
|
106
132
|
});
|
|
107
133
|
|
|
134
|
+
$effect(() => {
|
|
135
|
+
if (state.current === STATE_ABORTING) {
|
|
136
|
+
const { sourcesAborted, numberOfSources } = this.#abortProgress;
|
|
137
|
+
|
|
138
|
+
if (sourcesAborted === numberOfSources) {
|
|
139
|
+
// console.debug(`AudioScene: ${numberOfSources} sources aborted`);
|
|
140
|
+
this.#state.send(ABORTED);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
|
|
108
145
|
state.onenter = ( currentState ) => {
|
|
109
146
|
// console.log('onenter', currentState );
|
|
110
147
|
|
|
@@ -113,6 +150,11 @@ export default class AudioScene {
|
|
|
113
150
|
// console.log('AudioScene:loading');
|
|
114
151
|
this.#startLoading();
|
|
115
152
|
}
|
|
153
|
+
else if(currentState === STATE_ABORTING )
|
|
154
|
+
{
|
|
155
|
+
// console.log('AudioScene:aborting');
|
|
156
|
+
this.#startAbort();
|
|
157
|
+
}
|
|
116
158
|
|
|
117
159
|
this.state = state.current;
|
|
118
160
|
};
|
|
@@ -127,6 +169,13 @@ export default class AudioScene {
|
|
|
127
169
|
return this.#progress;
|
|
128
170
|
}
|
|
129
171
|
|
|
172
|
+
/**
|
|
173
|
+
* Get audio scene abort progress
|
|
174
|
+
*/
|
|
175
|
+
get abortProgress() {
|
|
176
|
+
return this.#abortProgress;
|
|
177
|
+
}
|
|
178
|
+
|
|
130
179
|
/**
|
|
131
180
|
* Start loading all audio sources
|
|
132
181
|
*/
|
|
@@ -134,6 +183,13 @@ export default class AudioScene {
|
|
|
134
183
|
this.#state.send(LOAD);
|
|
135
184
|
}
|
|
136
185
|
|
|
186
|
+
/**
|
|
187
|
+
* Abort loading all audio sources
|
|
188
|
+
*/
|
|
189
|
+
abort() {
|
|
190
|
+
this.#state.send(ABORT);
|
|
191
|
+
}
|
|
192
|
+
|
|
137
193
|
destroy() {
|
|
138
194
|
// TODO: disconnect all audio sources?
|
|
139
195
|
// TODO: Unload AUdioLoaders?
|
|
@@ -212,6 +268,14 @@ export default class AudioScene {
|
|
|
212
268
|
}
|
|
213
269
|
}
|
|
214
270
|
|
|
271
|
+
#startAbort() {
|
|
272
|
+
// console.log('#startAbort');
|
|
273
|
+
|
|
274
|
+
for (const { audioLoader } of this.#memorySources) {
|
|
275
|
+
audioLoader.abort();
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
215
279
|
/* ==== Audio specific */
|
|
216
280
|
|
|
217
281
|
/**
|
|
@@ -19,10 +19,21 @@ export default class ImageScene {
|
|
|
19
19
|
sourcesLoaded: number;
|
|
20
20
|
numberOfSources: number;
|
|
21
21
|
};
|
|
22
|
+
/**
|
|
23
|
+
* Get image scene abort progress
|
|
24
|
+
*/
|
|
25
|
+
get abortProgress(): {
|
|
26
|
+
sourcesAborted: number;
|
|
27
|
+
numberOfSources: number;
|
|
28
|
+
};
|
|
22
29
|
/**
|
|
23
30
|
* Start loading all image sources
|
|
24
31
|
*/
|
|
25
32
|
load(): void;
|
|
33
|
+
/**
|
|
34
|
+
* Abort loading all image sources
|
|
35
|
+
*/
|
|
36
|
+
abort(): void;
|
|
26
37
|
destroy(): void;
|
|
27
38
|
/**
|
|
28
39
|
* Add image source
|
|
@@ -8,8 +8,13 @@ import {
|
|
|
8
8
|
STATE_INITIAL,
|
|
9
9
|
STATE_LOADING,
|
|
10
10
|
STATE_LOADED,
|
|
11
|
+
STATE_ABORTING,
|
|
12
|
+
STATE_ABORTED,
|
|
13
|
+
STATE_ERROR,
|
|
11
14
|
LOAD,
|
|
12
|
-
LOADED
|
|
15
|
+
LOADED,
|
|
16
|
+
ABORT,
|
|
17
|
+
ABORTED
|
|
13
18
|
} from '../../../state/machines.js';
|
|
14
19
|
|
|
15
20
|
import ImageLoader from './ImageLoader.svelte.js';
|
|
@@ -70,6 +75,27 @@ export default class ImageScene {
|
|
|
70
75
|
};
|
|
71
76
|
});
|
|
72
77
|
|
|
78
|
+
#abortProgress = $derived.by(() => {
|
|
79
|
+
let sourcesAborted = 0;
|
|
80
|
+
const sources = this.#imageSources;
|
|
81
|
+
const numberOfSources = sources.length;
|
|
82
|
+
|
|
83
|
+
for (let j = 0; j < numberOfSources; j++) {
|
|
84
|
+
const source = sources[j];
|
|
85
|
+
const { imageLoader } = source;
|
|
86
|
+
const loaderState = imageLoader.state;
|
|
87
|
+
|
|
88
|
+
if (loaderState === STATE_ABORTED || loaderState === STATE_ERROR) {
|
|
89
|
+
sourcesAborted++;
|
|
90
|
+
}
|
|
91
|
+
} // end for
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
sourcesAborted,
|
|
95
|
+
numberOfSources
|
|
96
|
+
};
|
|
97
|
+
});
|
|
98
|
+
|
|
73
99
|
#sourcesLoaded = $derived( this.#progress.sourcesLoaded );
|
|
74
100
|
#numberOfSources = $derived( this.#progress.numberOfSources );
|
|
75
101
|
|
|
@@ -88,6 +114,17 @@ export default class ImageScene {
|
|
|
88
114
|
}
|
|
89
115
|
} );
|
|
90
116
|
|
|
117
|
+
$effect(() => {
|
|
118
|
+
if (state.current === STATE_ABORTING) {
|
|
119
|
+
const { sourcesAborted, numberOfSources } = this.#abortProgress;
|
|
120
|
+
|
|
121
|
+
if (sourcesAborted === numberOfSources) {
|
|
122
|
+
// console.debug(`ImageScene: ${numberOfSources} sources aborted`);
|
|
123
|
+
this.#state.send(ABORTED);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
|
|
91
128
|
state.onenter = ( currentState ) => {
|
|
92
129
|
// console.log('onenter', currentState );
|
|
93
130
|
|
|
@@ -96,6 +133,11 @@ export default class ImageScene {
|
|
|
96
133
|
// console.log('ImageScene:loading');
|
|
97
134
|
this.#startLoading();
|
|
98
135
|
}
|
|
136
|
+
else if(currentState === STATE_ABORTING )
|
|
137
|
+
{
|
|
138
|
+
// console.log('ImageScene:aborting');
|
|
139
|
+
this.#startAbort();
|
|
140
|
+
}
|
|
99
141
|
|
|
100
142
|
this.state = currentState;
|
|
101
143
|
};
|
|
@@ -110,6 +152,13 @@ export default class ImageScene {
|
|
|
110
152
|
return this.#progress;
|
|
111
153
|
}
|
|
112
154
|
|
|
155
|
+
/**
|
|
156
|
+
* Get image scene abort progress
|
|
157
|
+
*/
|
|
158
|
+
get abortProgress() {
|
|
159
|
+
return this.#abortProgress;
|
|
160
|
+
}
|
|
161
|
+
|
|
113
162
|
/**
|
|
114
163
|
* Start loading all image sources
|
|
115
164
|
*/
|
|
@@ -117,6 +166,13 @@ export default class ImageScene {
|
|
|
117
166
|
this.#state.send(LOAD);
|
|
118
167
|
}
|
|
119
168
|
|
|
169
|
+
/**
|
|
170
|
+
* Abort loading all image sources
|
|
171
|
+
*/
|
|
172
|
+
abort() {
|
|
173
|
+
this.#state.send(ABORT);
|
|
174
|
+
}
|
|
175
|
+
|
|
120
176
|
destroy() {
|
|
121
177
|
// TODO: disconnect all image sources?
|
|
122
178
|
// TODO: Unload ImageLoaders?
|
|
@@ -191,6 +247,12 @@ export default class ImageScene {
|
|
|
191
247
|
}
|
|
192
248
|
}
|
|
193
249
|
|
|
250
|
+
#startAbort() {
|
|
251
|
+
for (const { imageLoader } of this.#imageSources) {
|
|
252
|
+
imageLoader.abort();
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
194
256
|
/* ==== Internals */
|
|
195
257
|
|
|
196
258
|
/**
|
|
@@ -45,9 +45,9 @@ export default class NetworkLoader {
|
|
|
45
45
|
/**
|
|
46
46
|
* Abort the current loading operation
|
|
47
47
|
* - Only works when in STATE_LOADING
|
|
48
|
-
* - Aborts network requests and transitions to
|
|
48
|
+
* - Aborts network requests and transitions to STATE_ABORTING
|
|
49
49
|
*/
|
|
50
|
-
|
|
50
|
+
abort(): void;
|
|
51
51
|
/**
|
|
52
52
|
* Get network data size in bytes
|
|
53
53
|
* - Info comes from the content length response header
|
|
@@ -7,14 +7,14 @@ import {
|
|
|
7
7
|
STATE_LOADING,
|
|
8
8
|
STATE_UNLOADING,
|
|
9
9
|
STATE_LOADED,
|
|
10
|
-
|
|
11
|
-
STATE_ERROR,
|
|
10
|
+
STATE_ABORTING,
|
|
12
11
|
LOAD,
|
|
13
12
|
ERROR,
|
|
14
13
|
LOADED,
|
|
15
14
|
UNLOAD,
|
|
16
15
|
INITIAL,
|
|
17
|
-
|
|
16
|
+
ABORT,
|
|
17
|
+
ABORTED
|
|
18
18
|
} from '../../state/machines.js';
|
|
19
19
|
|
|
20
20
|
import * as expect from '../../util/expect.js';
|
|
@@ -123,21 +123,23 @@ export default class NetworkLoader {
|
|
|
123
123
|
}
|
|
124
124
|
break;
|
|
125
125
|
|
|
126
|
-
case
|
|
126
|
+
case STATE_ABORTING:
|
|
127
127
|
{
|
|
128
|
-
// console.log('NetworkLoader:
|
|
128
|
+
// console.log('NetworkLoader:aborting');
|
|
129
129
|
if (this._abortLoading) {
|
|
130
130
|
this._abortLoading();
|
|
131
131
|
this._abortLoading = null;
|
|
132
132
|
}
|
|
133
|
+
// Transition to aborted state after abort completes
|
|
134
|
+
this._state.send(ABORTED);
|
|
133
135
|
}
|
|
134
136
|
break;
|
|
135
137
|
|
|
136
|
-
case STATE_ERROR:
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
138
|
+
// case STATE_ERROR:
|
|
139
|
+
// {
|
|
140
|
+
// console.log('NetworkLoader:error', state.error);
|
|
141
|
+
// }
|
|
142
|
+
// break;
|
|
141
143
|
} // end switch
|
|
142
144
|
};
|
|
143
145
|
}
|
|
@@ -160,10 +162,10 @@ export default class NetworkLoader {
|
|
|
160
162
|
/**
|
|
161
163
|
* Abort the current loading operation
|
|
162
164
|
* - Only works when in STATE_LOADING
|
|
163
|
-
* - Aborts network requests and transitions to
|
|
165
|
+
* - Aborts network requests and transitions to STATE_ABORTING
|
|
164
166
|
*/
|
|
165
|
-
|
|
166
|
-
this._state.send(
|
|
167
|
+
abort() {
|
|
168
|
+
this._state.send(ABORT);
|
|
167
169
|
}
|
|
168
170
|
|
|
169
171
|
/**
|
|
@@ -10,13 +10,13 @@ export default class LoadingStateMachine extends FiniteStateMachine {
|
|
|
10
10
|
* - Only valid when currently loading
|
|
11
11
|
* - Useful for external timeout management
|
|
12
12
|
*/
|
|
13
|
-
|
|
13
|
+
timeout(): void;
|
|
14
14
|
/**
|
|
15
|
-
* Transition to
|
|
15
|
+
* Transition to aborting state
|
|
16
16
|
* - Only valid when currently loading
|
|
17
|
-
* - Useful for external
|
|
17
|
+
* - Useful for external abort management
|
|
18
18
|
*/
|
|
19
|
-
|
|
19
|
+
abort(): void;
|
|
20
20
|
#private;
|
|
21
21
|
}
|
|
22
22
|
import FiniteStateMachine from '../finite-state-machine/FiniteStateMachine.svelte.js';
|
|
@@ -8,14 +8,16 @@ import {
|
|
|
8
8
|
STATE_LOADING,
|
|
9
9
|
STATE_UNLOADING,
|
|
10
10
|
STATE_LOADED,
|
|
11
|
-
|
|
11
|
+
STATE_ABORTING,
|
|
12
|
+
STATE_ABORTED,
|
|
12
13
|
STATE_ERROR,
|
|
13
14
|
STATE_TIMEOUT,
|
|
14
15
|
|
|
15
16
|
// > Signals
|
|
16
17
|
INITIAL,
|
|
17
18
|
LOAD,
|
|
18
|
-
|
|
19
|
+
ABORT,
|
|
20
|
+
ABORTED,
|
|
19
21
|
ERROR,
|
|
20
22
|
LOADED,
|
|
21
23
|
UNLOAD,
|
|
@@ -41,7 +43,7 @@ export default class LoadingStateMachine extends FiniteStateMachine {
|
|
|
41
43
|
// _enter: () => {
|
|
42
44
|
// console.log('LoadingStateMachine: enter LOADING');
|
|
43
45
|
// },
|
|
44
|
-
[
|
|
46
|
+
[ABORT]: STATE_ABORTING,
|
|
45
47
|
[ERROR]: STATE_ERROR,
|
|
46
48
|
[LOADED]: STATE_LOADED,
|
|
47
49
|
[TIMEOUT]: STATE_TIMEOUT
|
|
@@ -57,7 +59,11 @@ export default class LoadingStateMachine extends FiniteStateMachine {
|
|
|
57
59
|
[ERROR]: STATE_ERROR,
|
|
58
60
|
[INITIAL]: STATE_INITIAL
|
|
59
61
|
},
|
|
60
|
-
[
|
|
62
|
+
[STATE_ABORTING]: {
|
|
63
|
+
[ERROR]: STATE_ERROR,
|
|
64
|
+
[ABORTED]: STATE_ABORTED
|
|
65
|
+
},
|
|
66
|
+
[STATE_ABORTED]: {
|
|
61
67
|
[LOAD]: STATE_LOADING,
|
|
62
68
|
[UNLOAD]: STATE_UNLOADING
|
|
63
69
|
},
|
|
@@ -99,16 +105,16 @@ export default class LoadingStateMachine extends FiniteStateMachine {
|
|
|
99
105
|
* - Only valid when currently loading
|
|
100
106
|
* - Useful for external timeout management
|
|
101
107
|
*/
|
|
102
|
-
|
|
108
|
+
timeout() {
|
|
103
109
|
this.send(TIMEOUT);
|
|
104
110
|
}
|
|
105
111
|
|
|
106
112
|
/**
|
|
107
|
-
* Transition to
|
|
113
|
+
* Transition to aborting state
|
|
108
114
|
* - Only valid when currently loading
|
|
109
|
-
* - Useful for external
|
|
115
|
+
* - Useful for external abort management
|
|
110
116
|
*/
|
|
111
|
-
|
|
112
|
-
this.send(
|
|
117
|
+
abort() {
|
|
118
|
+
this.send(ABORT);
|
|
113
119
|
}
|
|
114
120
|
}
|
|
@@ -4,17 +4,18 @@ A specialized finite state machine designed for managing loading operations with
|
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
|
-
`LoadingStateMachine` extends `FiniteStateMachine` to provide a standardized way to handle loading workflows. It includes predefined states for initial, loading, loaded, unloading,
|
|
7
|
+
`LoadingStateMachine` extends `FiniteStateMachine` to provide a standardized way to handle loading workflows. It includes predefined states for initial, loading, loaded, unloading, aborted, and error conditions.
|
|
8
8
|
|
|
9
9
|
## States
|
|
10
10
|
|
|
11
|
-
The machine defines
|
|
11
|
+
The machine defines eight primary states:
|
|
12
12
|
|
|
13
13
|
- **`INITIAL`** - Starting state, ready to begin loading
|
|
14
14
|
- **`LOADING`** - Currently loading data or resources
|
|
15
15
|
- **`LOADED`** - Successfully loaded, data available
|
|
16
16
|
- **`UNLOADING`** - Cleaning up or releasing resources
|
|
17
|
-
- **`
|
|
17
|
+
- **`ABORTING`** - Currently aborting loading operation
|
|
18
|
+
- **`ABORTED`** - Loading operation was aborted
|
|
18
19
|
- **`ERROR`** - An error occurred during loading
|
|
19
20
|
- **`TIMEOUT`** - Loading operation exceeded time limit
|
|
20
21
|
|
|
@@ -25,7 +26,8 @@ Available events to trigger state transitions:
|
|
|
25
26
|
- **`LOAD`** - Start loading operation
|
|
26
27
|
- **`LOADED`** - Mark loading as complete
|
|
27
28
|
- **`UNLOAD`** - Begin cleanup/unloading
|
|
28
|
-
- **`
|
|
29
|
+
- **`ABORT`** - Start aborting the loading operation
|
|
30
|
+
- **`ABORTED`** - Mark abort operation as complete
|
|
29
31
|
- **`ERROR`** - Signal an error occurred
|
|
30
32
|
- **`TIMEOUT`** - Signal operation has timed out
|
|
31
33
|
- **`INITIAL`** - Return to initial state
|
|
@@ -44,7 +46,7 @@ import {
|
|
|
44
46
|
LOAD,
|
|
45
47
|
LOADED,
|
|
46
48
|
ERROR,
|
|
47
|
-
|
|
49
|
+
ABORT
|
|
48
50
|
} from '$lib/state/machines.js';
|
|
49
51
|
|
|
50
52
|
const loader = new LoadingStateMachine();
|
|
@@ -67,10 +69,11 @@ console.log(loader.current); // STATE_LOADED
|
|
|
67
69
|
|
|
68
70
|
```
|
|
69
71
|
INITIAL → LOADING
|
|
70
|
-
LOADING → LOADED |
|
|
72
|
+
LOADING → LOADED | ABORTING | ERROR | TIMEOUT
|
|
71
73
|
LOADED → LOADING | UNLOADING
|
|
72
74
|
UNLOADING → INITIAL | ERROR
|
|
73
|
-
|
|
75
|
+
ABORTING → ABORTED | ERROR
|
|
76
|
+
ABORTED → LOADING | UNLOADING
|
|
74
77
|
ERROR → LOADING | UNLOADING
|
|
75
78
|
TIMEOUT → LOADING | UNLOADING
|
|
76
79
|
```
|
|
@@ -78,26 +81,26 @@ TIMEOUT → LOADING | UNLOADING
|
|
|
78
81
|
### Transition Diagram
|
|
79
82
|
|
|
80
83
|
```
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
┌─────────┐
|
|
87
|
-
│ LOADING
|
|
88
|
-
└────┬────┘
|
|
89
|
-
│
|
|
90
|
-
|
|
91
|
-
│
|
|
92
|
-
▼
|
|
93
|
-
┌────────┐ ┌───────┐
|
|
94
|
-
│ LOADED │ │ ERROR │
|
|
95
|
-
└────┬───┘ └───┬───┘
|
|
96
|
-
│ │
|
|
97
|
-
UNLOAD│
|
|
98
|
-
▼ ▼
|
|
99
|
-
|
|
100
|
-
│UNLOADING
|
|
84
|
+
┌─────────┐
|
|
85
|
+
│ INITIAL │
|
|
86
|
+
└────┬────┘
|
|
87
|
+
LOAD│
|
|
88
|
+
▼
|
|
89
|
+
┌─────────┐ ABORT ┌──────────┐
|
|
90
|
+
│ LOADING │──────────────────────────────→│ ABORTING │
|
|
91
|
+
└────┬────┘ └─────┬────┘
|
|
92
|
+
│ │
|
|
93
|
+
LOADED│ ERROR TIMEOUT ABORTED │ERROR
|
|
94
|
+
│ │ │ │ │
|
|
95
|
+
▼ ▼ ▼ ▼ ▼
|
|
96
|
+
┌────────┐ ┌───────┐ ┌─────────┐ ┌─────────┐
|
|
97
|
+
│ LOADED │ │ ERROR │ │ TIMEOUT │ │ ABORTED │
|
|
98
|
+
└────┬───┘ └───┬───┘ └────┬────┘ └────┬────┘
|
|
99
|
+
│ │ │ │
|
|
100
|
+
UNLOAD│ LOAD│UNLOAD LOAD│UNLOAD LOAD│UNLOAD
|
|
101
|
+
▼ ▼ ▼ ▼
|
|
102
|
+
┌──────────┐ │
|
|
103
|
+
│UNLOADING │◄────────────────────────────────┘
|
|
101
104
|
└──────────┘
|
|
102
105
|
```
|
|
103
106
|
|
|
@@ -184,7 +187,7 @@ const loader = new LoadingStateMachine();
|
|
|
184
187
|
// External timeout management
|
|
185
188
|
const timeoutId = setTimeout(() => {
|
|
186
189
|
if (loader.current === STATE_LOADING) {
|
|
187
|
-
loader.
|
|
190
|
+
loader.timeout(); // Transitions to STATE_TIMEOUT
|
|
188
191
|
}
|
|
189
192
|
}, 10000); // 10 second timeout
|
|
190
193
|
|
|
@@ -201,13 +204,22 @@ loader.onenter = (currentState) => {
|
|
|
201
204
|
};
|
|
202
205
|
```
|
|
203
206
|
|
|
204
|
-
###
|
|
207
|
+
### timeout Method
|
|
205
208
|
|
|
206
|
-
Use `
|
|
209
|
+
Use `timeout()` to manually trigger a timeout transition:
|
|
207
210
|
|
|
208
211
|
```javascript
|
|
209
212
|
// Only works when in STATE_LOADING
|
|
210
|
-
loader.
|
|
213
|
+
loader.timeout(); // Sends TIMEOUT signal
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### abort Method
|
|
217
|
+
|
|
218
|
+
Use `abort()` to manually trigger an abort transition:
|
|
219
|
+
|
|
220
|
+
```javascript
|
|
221
|
+
// Only works when in STATE_LOADING
|
|
222
|
+
loader.abort(); // Sends ABORT signal, transitions to STATE_ABORTING
|
|
211
223
|
```
|
|
212
224
|
|
|
213
225
|
## Integration with Svelte Reactivity
|
|
@@ -313,7 +325,7 @@ export default class MultiSourceLoader {
|
|
|
313
325
|
LOAD,
|
|
314
326
|
LOADED,
|
|
315
327
|
ERROR,
|
|
316
|
-
|
|
328
|
+
ABORT
|
|
317
329
|
} from '$lib/state/machines.js';
|
|
318
330
|
|
|
319
331
|
const loader = new LoadingStateMachine();
|
|
@@ -351,7 +363,7 @@ export default class MultiSourceLoader {
|
|
|
351
363
|
{/if}
|
|
352
364
|
```
|
|
353
365
|
|
|
354
|
-
### Advanced Component with
|
|
366
|
+
### Advanced Component with Abort Handling
|
|
355
367
|
|
|
356
368
|
```javascript
|
|
357
369
|
<script>
|
|
@@ -360,12 +372,14 @@ export default class MultiSourceLoader {
|
|
|
360
372
|
STATE_INITIAL,
|
|
361
373
|
STATE_LOADING,
|
|
362
374
|
STATE_LOADED,
|
|
363
|
-
|
|
375
|
+
STATE_ABORTING,
|
|
376
|
+
STATE_ABORTED,
|
|
364
377
|
STATE_ERROR,
|
|
365
378
|
LOAD,
|
|
366
379
|
LOADED,
|
|
367
380
|
ERROR,
|
|
368
|
-
|
|
381
|
+
ABORT,
|
|
382
|
+
ABORTED
|
|
369
383
|
} from '$lib/state/machines.js';
|
|
370
384
|
|
|
371
385
|
const loader = new LoadingStateMachine();
|
|
@@ -376,8 +390,11 @@ export default class MultiSourceLoader {
|
|
|
376
390
|
case STATE_LOADING:
|
|
377
391
|
startLoad();
|
|
378
392
|
break;
|
|
379
|
-
case
|
|
393
|
+
case STATE_ABORTING:
|
|
394
|
+
// Start abort process
|
|
380
395
|
abortController?.abort();
|
|
396
|
+
// Simulate abort completion
|
|
397
|
+
setTimeout(() => loader.send(ABORTED), 100);
|
|
381
398
|
break;
|
|
382
399
|
}
|
|
383
400
|
};
|
|
@@ -393,7 +410,7 @@ export default class MultiSourceLoader {
|
|
|
393
410
|
loader.send(LOADED);
|
|
394
411
|
} catch (error) {
|
|
395
412
|
if (error.name === 'AbortError') {
|
|
396
|
-
// Request was
|
|
413
|
+
// Request was aborted, machine will transition to STATE_ABORTED
|
|
397
414
|
} else {
|
|
398
415
|
loader.send(ERROR, error);
|
|
399
416
|
}
|
|
@@ -405,13 +422,15 @@ export default class MultiSourceLoader {
|
|
|
405
422
|
{#if loader.current === STATE_INITIAL}
|
|
406
423
|
<button onclick={() => loader.send(LOAD)}>Start Loading</button>
|
|
407
424
|
{:else if loader.current === STATE_LOADING}
|
|
408
|
-
<button onclick={() => loader.send(
|
|
425
|
+
<button onclick={() => loader.send(ABORT)}>Abort Loading</button>
|
|
409
426
|
<div>Loading data...</div>
|
|
427
|
+
{:else if loader.current === STATE_ABORTING}
|
|
428
|
+
<div>Aborting...</div>
|
|
410
429
|
{:else if loader.current === STATE_LOADED}
|
|
411
430
|
<div>Data loaded successfully!</div>
|
|
412
431
|
<button onclick={() => loader.send(LOAD)}>Reload</button>
|
|
413
|
-
{:else if loader.current ===
|
|
414
|
-
<div>Loading
|
|
432
|
+
{:else if loader.current === STATE_ABORTED}
|
|
433
|
+
<div>Loading aborted</div>
|
|
415
434
|
<button onclick={() => loader.send(LOAD)}>Try Again</button>
|
|
416
435
|
{:else if loader.current === STATE_ERROR}
|
|
417
436
|
<div>Error: {loader.error.message}</div>
|
|
@@ -449,8 +468,11 @@ loader.onenter = (currentState) => {
|
|
|
449
468
|
showErrorToast(loader.error.message);
|
|
450
469
|
logError(loader.error);
|
|
451
470
|
break;
|
|
452
|
-
case
|
|
453
|
-
showMessage('
|
|
471
|
+
case STATE_ABORTING:
|
|
472
|
+
showMessage('Aborting operation...');
|
|
473
|
+
break;
|
|
474
|
+
case STATE_ABORTED:
|
|
475
|
+
showMessage('Operation aborted');
|
|
454
476
|
break;
|
|
455
477
|
}
|
|
456
478
|
};
|
|
@@ -466,7 +488,8 @@ loader.onenter = (currentState) => {
|
|
|
466
488
|
break;
|
|
467
489
|
case STATE_LOADED:
|
|
468
490
|
case STATE_ERROR:
|
|
469
|
-
case
|
|
491
|
+
case STATE_ABORTING:
|
|
492
|
+
case STATE_ABORTED:
|
|
470
493
|
hideProgressBar();
|
|
471
494
|
break;
|
|
472
495
|
case STATE_UNLOADING:
|
|
@@ -576,7 +599,8 @@ import {
|
|
|
576
599
|
STATE_LOADING,
|
|
577
600
|
STATE_LOADED,
|
|
578
601
|
STATE_UNLOADING,
|
|
579
|
-
|
|
602
|
+
STATE_ABORTING,
|
|
603
|
+
STATE_ABORTED,
|
|
580
604
|
STATE_ERROR,
|
|
581
605
|
STATE_TIMEOUT,
|
|
582
606
|
|
|
@@ -584,7 +608,8 @@ import {
|
|
|
584
608
|
LOAD,
|
|
585
609
|
LOADED,
|
|
586
610
|
UNLOAD,
|
|
587
|
-
|
|
611
|
+
ABORT,
|
|
612
|
+
ABORTED,
|
|
588
613
|
ERROR,
|
|
589
614
|
INITIAL,
|
|
590
615
|
TIMEOUT
|
|
@@ -2,12 +2,14 @@ export const STATE_INITIAL: "initial";
|
|
|
2
2
|
export const STATE_LOADING: "loading";
|
|
3
3
|
export const STATE_UNLOADING: "unloading";
|
|
4
4
|
export const STATE_LOADED: "loaded";
|
|
5
|
-
export const
|
|
5
|
+
export const STATE_ABORTING: "aborting";
|
|
6
|
+
export const STATE_ABORTED: "aborted";
|
|
6
7
|
export const STATE_ERROR: "error";
|
|
7
8
|
export const STATE_TIMEOUT: "timeout";
|
|
8
9
|
export const INITIAL: "initial";
|
|
9
10
|
export const LOAD: "load";
|
|
10
|
-
export const
|
|
11
|
+
export const ABORT: "abort";
|
|
12
|
+
export const ABORTED: "aborted";
|
|
11
13
|
export const ERROR: "error";
|
|
12
14
|
export const LOADED: "loaded";
|
|
13
15
|
export const UNLOAD: "unload";
|
|
@@ -3,7 +3,8 @@ export const STATE_LOADING = 'loading';
|
|
|
3
3
|
export const STATE_UNLOADING = 'unloading';
|
|
4
4
|
export const STATE_LOADED = 'loaded';
|
|
5
5
|
|
|
6
|
-
export const
|
|
6
|
+
export const STATE_ABORTING = 'aborting';
|
|
7
|
+
export const STATE_ABORTED = 'aborted';
|
|
7
8
|
export const STATE_ERROR = 'error';
|
|
8
9
|
export const STATE_TIMEOUT = 'timeout';
|
|
9
10
|
|
|
@@ -11,7 +12,8 @@ export const STATE_TIMEOUT = 'timeout';
|
|
|
11
12
|
|
|
12
13
|
export const INITIAL = 'initial';
|
|
13
14
|
export const LOAD = 'load';
|
|
14
|
-
export const
|
|
15
|
+
export const ABORT = 'abort';
|
|
16
|
+
export const ABORTED = 'aborted';
|
|
15
17
|
export const ERROR = 'error';
|
|
16
18
|
export const LOADED = 'loaded';
|
|
17
19
|
export const UNLOAD = 'unload';
|