Skip to content

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 ​

typescript
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 ​

typescript
// Listen to event only once
event.once('notification', (message) => {
    console.log('Notification received:', message.payload);
});

Using Wildcards ​

typescript
// 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:

ts
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:

typescript
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:

typescript
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:

typescript
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:

typescript
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:

typescript
import { 
FastEvent
} from 'fastevent';
const
emitter
= new
FastEvent
();
emitter
.
on
(
'event', (
message
,
args
) => {
}, { // Event listener arguments }, );

args is an object containing these fields:

ts
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:

typescript
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: '**'
  • listener: Event listener function receiving event message object
  • options: Optional configuration
    • count: Trigger count limit, 0 means unlimited
    • prepend: Whether to prepend listener to queue
    • filter: Event filter function
typescript
// 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.

typescript
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('**').

typescript
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.

typescript
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:

ts
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:

  1. Single-level wildcard (*): Matches single-level paths
typescript
// Matches user/login, user/logout etc.
event.on('user/*', (message) => {
    console.log('User action:', message.type);
});
  1. Multi-level wildcard (**): Matches multi-level paths
typescript
// 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.

typescript
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:

typescript
// 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:

ts
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:

ts
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:

ts
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:

typescript
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}`);
});