Error Handling
When a state transition fails, AFSM throws an FSMError and rolls back the state.
State validation failure
If the current state isn’t in from, an error is thrown immediately:
class Conn extends FSM { @ChangeState(FSM.INIT, 'connected') async connect() {} @ChangeState('connected', 'ready') async prepare() {}}
const c = new Conn()await c.prepare() // FSMError: current state [*] not from connectedError message format:
Conn prepare to ready failed: current state [*] not from connectedMethod execution failure
Errors thrown by the original method are wrapped in FSMError:
@ChangeState('idle', 'done')async fetch() { throw new Error('network down')}- State goes
idle→fetching→ rolls back toidle fetch()rejects with anFSMErrorwhosecausepoints to the originalError
FSMError type
export class FSMError extends Error { state: State // state at the time of error message: string cause?: Error // original error (if any)}try { await obj.fetch()} catch (e) { if (e instanceof FSMError) { console.log(e.state) // 'idle' console.log(e.cause) // Error: network down }}ignoreError — don’t throw
@ChangeState('idle', 'done', { ignoreError: true })async fetch() { throw new Error('oops')}
const r = await obj.fetch()// r is an FSMError instance, not a rejection// state still rolls back to idlefail callback
@ChangeState('idle', 'done', { fail: (err: FSMError) => reportError(err)})async fetch() {}fail is called after rollback, before returning to the caller. this refers to the instance.
Errors in sync mode
With sync: true (see Sync Mode), errors are thrown instead of rejected:
@ChangeState('idle', 'done', { sync: true })init() { throw new Error('bad')}
try { obj.init()} catch (e) { // e is an FSMError}With ignoreError also on, the error is returned instead of thrown.
Full example
Lower the “success rate” slider to watch failure rollbacks and FSMError.