Event Subscription
FastEvent provides a powerful and flexible event subscription system supporting multiple subscription patterns and matching modes. You can use simple APIs to listen to specific events, one-time events, or all events, and also use wildcards to match multiple events.
Quick Start
Basic Subscription
import { FastEvent } from '@fastevent/core';
const event = new FastEvent();
// Subscribe to specific event
event.on('user/login', (message) => {
console.log('User login:', message.payload);
});
// Emit event
event.emit('user/login', { userId: 123 });
One-time Subscription
// Listen to event only once
event.once('notification', (message) => {
console.log('Notification received:', message.payload);
});
Using Wildcards
// Listen to all user-related events
event.on('user/*', (message) => {
console.log('User event:', message.type, message.payload);
});
// Listen to all events
event.onAny((message) => {
console.log('Global event:', message.type, message.payload);
});
Guide
Event Listeners
When subscribing to events, you need to provide an event listener function to receive event messages. The listener function signature is:
type FastEventListener = (
message: FastEventMessage, // Event message
args: FastEventListenerArgs, // Event message arguments
) => any | Promise<any>;
FastEventListener
is a regular function type that can be synchronous or asynchronous, receiving an event message object as parameter and returning any type.
Context (Execution Context)
The listener's this
context defaults to the FastEvent
instance:
const emitter = new FastEvent();
emitter.on('event', function (this, message, args) {
this === emitter; // true
});
You can override the default context by specifying the context
property when creating the FastEvent
instance:
const emitter = new FastEvent(
context: 100
);
emitter.on('event', function (this, message, args) {
this === 100; // true
});
Event Message Format
FastEvent uses standardized message format for all events to ensure consistency and extensibility.
All event listeners receive a standardized message object FastEventMessage
:
interface FastEventMessage<T = string, P = any, M = Record<string, unknown>> {
type: T; // Event type identifier
payload: P; // Event data payload
meta: M; // Event metadata
}
- Field Details
Field | Type | Description |
---|---|---|
type | string | Event name |
payload | any | Event data payload |
meta | Record<string, unknown> | Event metadata |
- Message Extension
FastEvent
uses FastEventMessage
as the message object. You can extend the message object using the FastEventMessageExtends
interface:
declare module 'fast-event' {
interface FastEventMessageExtends {
// Custom fields
}
}
Listener Arguments
FastEvent
supports passing arguments when subscribing, which are passed to listeners to control their behavior:
import { FastEvent } from 'fastevent';
const emitter = new FastEvent();
emitter.on(
'event',
(message, args) => {
},
{
// Event listener arguments
},
);
args
is an object containing these fields:
type FastEventListenerArgs<M = Record<string, any>> = {
retain?: boolean;
meta?: Record<string, any> & Partial<M>;
abortSignal?: AbortSignal; // For passing to listener functions
executor?: FastListenerExecutorArgs;
};
Subscription Methods
Basic Subscription - on
The on()
method is the most basic subscription method for listening to specific event types:
event.on(type, listener, options?);
Parameter description:
type
: Event type, supporting these formats:- Regular string:
'user/login'
- Single-level wildcard:
'user/*'
(matches one level) - Multi-level wildcard:
'user/**'
(matches multiple levels) - Global listener:
'**'
- Regular string:
listener
: Event listener function receiving event message objectoptions
: Optional configurationcount
: Trigger count limit, 0 means unlimitedprepend
: Whether to prepend listener to queuefilter
: Event filter function
// Basic usage
event.on('chat/message', (message) => {
console.log('Message received:', message.payload);
});
// Using options
event.on(
'user/login',
(message) => {
console.log('User login:', message.payload);
},
{
count: 3, // Trigger only 3 times
prepend: true, // Prepend to listener queue
},
);
// Using filter
event.on(
'data/update',
(message) => {
console.log('Data updated:', message.payload);
},
{
filter: (message) => message.payload.important === true,
},
);
One-time Subscription - once
The once()
method creates a listener that triggers only once. This is a special case of on()
, equivalent to setting options.count = 1
.
event.once('server/start', (message) => {
console.log('Server started:', message.payload);
});
Subscribe All Events - onAny
The onAny()
method listens to all events, shorthand for on('**')
.
event.onAny((message) => {
console.log('Event type:', message.type);
console.log('Event data:', message.payload);
});
Default Listener
When using on/once/onAny
to subscribe to events, you can omit the listener function, in which case the default listener onMessage
will be used.
const emitter = new FastEvent();
// Default listener
emitter.onMessage = (message) => {
console.log('Event received:', message.type);
};
// Subscribe events to default listener
emitter.on('user/login');
emitter.once('user/logout');
emitter.onAny();
onMessage
is typically used more for class inheritance:
class MyEmitter extends FastEvent {
onMessage(message) {
console.log('Event received:', message.type);
}
}
const emitter = new MyEmitter();
// Subscribe events to default listener
emitter.on('user/login');
emitter.once('user/logout');
emitter.onAny();
Wildcard Matching
FastEvent supports two types of wildcards:
- Single-level wildcard (
*
): Matches single-level paths
// Matches user/login, user/logout etc.
event.on('user/*', (message) => {
console.log('User action:', message.type);
});
- Multi-level wildcard (
**
): Matches multi-level paths
// Matches user/profile/update, user/settings/theme/change etc.
event.on('user/**', (message) => {
console.log('User-related event:', message.type);
});
**
can match any number of path levels, but only works at the end of event names.
event.on('user/**', listener); // ✅ Valid
event.on('user/**/login', listener); // ❌ Invalid
Event Retention
FastEvent
supports event retention (retain
) feature, allowing new subscribers to immediately receive the last retained event:
// Emit and retain event
event.emit('status/update', { online: true }, true); // Third parameter true means retain event
event.emit(
'status/update',
{ online: true },
{
retain: true, // Retain event
},
);
// Subsequent subscribers immediately receive retained event
event.on('status/update', (message) => {
console.log('Current status:', message.payload); // Immediately outputs: Current status: { online: true }
});
Subscription Count
FastEvent
supports the count
parameter to limit listener execution count. When the count is reached, the subscription is automatically removed:
event.on('status/update', listener, { count: 3 }); // Trigger only 3 times
Note
event.once
is a special case of on()
, equivalent to on(event,listener,{count:1})
Listener Priority
By default, listeners are appended to the queue in subscription order. You can use the prepend
parameter to insert listeners at the head of the queue:
event.on('event', () => 1); // Default append to queue tail
event.on('event', () => 2, { prepend: true }); // Insert at queue head
event.emit('event'); // Output: 2 1
Event Filtering
FastEvent
supports the filter
parameter to filter events - only events passing the filter will trigger:
event.on('event', (message) => {}, {
filter: (message, args) => message.payload.userId === '123',
});
Type Safety
FastEvent fully supports TypeScript. You can define event types for complete type checking:
interface MyEvents {
'user/login': { userId: string; timestamp: number };
'user/logout': { userId: string };
}
const event = new FastEvent<MyEvents>();
// Type-safe event subscription
event.on('user/login', (message) => {
// message.payload type is { userId: string; timestamp: number }
console.log(`User ${message.payload.userId} logged in at ${message.payload.timestamp}`);
});