npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

hd-pub-sub

v1.0.6

Published

一个类型安全、轻量级的事件发布订阅系统,支持异步事件处理和灵活的订阅管理。

Readme

hd-pub-sub 事件系统

一个类型安全、轻量级的事件发布订阅系统,支持异步事件处理和灵活的订阅管理。

特性

  • 🎯 完全类型安全 - 使用 TypeScript 泛型提供完整的类型推断
  • 异步事件处理 - 所有监听器异步执行,避免阻塞主线程
  • 🔧 灵活订阅管理 - 支持批量取消订阅和指定监听器移除
  • 🛡️ 错误处理 - 内置错误捕获和警告提示
  • 📦 零依赖 - 纯 TypeScript 实现,无需额外依赖

安装

npm install hd-pub-sub
# 或
yarn add hd-pub-sub
# 或
pnpm add hd-pub-sub

快速开始

1. 定义事件类型

首先,定义你的应用事件类型:

// events.ts
export type AppEvents = {
  'user:login': (userId: string, timestamp: Date) => void;
  'user:logout': (userId: string) => void;
  'notification:new': (message: string, type: 'info' | 'warning' | 'error') => void;
  'cart:update': (itemCount: number, total: number) => void;
};

2. 创建 PubSub 实例

// pubsub.ts
import createPubSub from 'hd-pub-sub';
import { AppEvents } from './events';

const pubSub = createPubSub<AppEvents>();

export default pubSub;

3. 使用事件系统

import pubSub from './pubsub';

// 订阅事件
const handleLogin = (userId: string, timestamp: Date) => {
  console.log(`用户 ${userId} 登录于 ${timestamp}`);
};

pubSub.subscribe('user:login', handleLogin);

// 订阅仅触发一次事件
pubSub.subscribe('user:login', handleLogin, { once: true });

// 发布事件
pubSub.publish('user:login', 'user-123', new Date());

// 取消订阅特定监听器
pubSub.unsubscribe('user:login', handleLogin);

// 取消事件的所有监听器
pubSub.unsubscribe('user:login');

// 清除所有事件监听器
pubSub.unsubscribe();

API 文档

createPubSub()

创建一个类型安全的事件发布订阅实例。

类型参数:

  • T: 事件类型定义,必须是 Record<string | number | symbol, (...args: any) => void> 的子类型

返回值: 包含三个方法的对象:

  • subscribe: 订阅事件
  • unsubscribe: 取消订阅
  • publish: 发布事件

subscribe(event: K, listener: T[K])

订阅指定事件。

参数:

  • event: K - 事件名称
  • listener: T[K] - 事件监听器函数

特性:

  • 自动避免重复订阅同一监听器
  • 重复订阅时会显示警告
  • 自动创建新事件的监听器数组

示例:

pubSub.subscribe('notification:new', (message, type) => {
  console.log(`[${type}] ${message}`);
});

unsubscribe(event?: K, listener?: T[K])

取消事件订阅。

参数组合和行为:

| 参数组合 | 行为 | | ---------------------------------- | ---------------------------------- | | unsubscribe() | 清除所有事件的所有监听器 | | unsubscribe('user:login') | 清除 user:login 事件的所有监听器 | | unsubscribe('user:login', handler) | 仅清除 user:login 事件的指定监听器 |

示例:

// 情况1:清除所有监听器
pubSub.unsubscribe();

// 情况2:清除特定事件的所有监听器
pubSub.unsubscribe('user:login');

// 情况3:清除特定事件的特定监听器
const handler = (userId: string) => { /* ... */ };
pubSub.subscribe('user:logout', handler);
pubSub.unsubscribe('user:logout', handler);

publish(event: K, ...args: Parameters<T[K]>)

发布事件,触发所有订阅的监听器。

参数:

  • event: K - 要发布的事件名称
  • ...args: Parameters<T[K]> - 传递给监听器的参数

特性:

  • 异步执行所有监听器(使用 setTimeout 延迟 0ms)
  • 自动处理没有订阅者的情况
  • 内置错误捕获,单个监听器错误不会影响其他监听器

示例:

// 发布事件,自动推断参数类型
pubSub.publish('cart:update', 5, 199.99);

// 类型安全 - 下面的代码会报错:
// pubSub.publish('cart:update', 'five'); // 错误:参数类型不匹配

高级用法

创建多个独立的事件总线

// 用户相关事件
const userEvents = createPubSub<{
  'profile:updated': (user: User) => void;
  'settings:changed': (settings: UserSettings) => void;
}>();

// 应用状态事件
const appEvents = createPubSub<{
  'app:loaded': () => void;
  'app:error': (error: Error) => void;
}>();

// UI 事件
const uiEvents = createPubSub<{
  'modal:open': (modalId: string) => void;
  'modal:close': (modalId: string) => void;
}>();

组合事件处理

// 创建一个事件代理,将多个事件总线合并
const eventHub = {
  user: userEvents,
  app: appEvents,
  ui: uiEvents,
};

// 使用
eventHub.user.subscribe('profile:updated', handleProfileUpdate);
eventHub.app.publish('app:loaded');

错误处理示例

pubSub.subscribe('app:error', (error: Error) => {
  // 发送错误到监控服务
  monitoringService.captureException(error);
  
  // 显示用户友好的错误消息
  if (error instanceof NetworkError) {
    showToast('网络连接失败,请检查网络设置');
  }
});

// 在应用中捕获并发布错误
try {
  // 某些可能失败的操作
} catch (error) {
  pubSub.publish('app:error', error);
}

性能优化技巧

// 1. 避免在频繁触发的事件中使用昂贵的操作
pubSub.subscribe('scroll:position', (position) => {
  // 使用防抖或节流处理频繁事件
  debouncedUpdateUI(position);
});

// 2. 及时清理不再需要的事件监听器
class UserComponent {
  private loginHandler: (userId: string) => void;

  constructor() {
    this.loginHandler = this.handleLogin.bind(this);
    pubSub.subscribe('user:login', this.loginHandler);
  }

  destroy() {
    // 组件销毁时取消订阅
    pubSub.unsubscribe('user:login', this.loginHandler);
  }

  private handleLogin(userId: string) {
    // 处理登录逻辑
  }
}

类型定义

// 基础事件类型
export type StoreValue = any;

export type BasePubSub = Record<
  string | number | symbol,
  (...args: StoreValue) => void
>;

// 创建函数类型
declare function createPubSub<T extends BasePubSub>(): {
  subscribe: <K extends keyof T>(event: K, listener: T[K]) => void;
  unsubscribe: <K extends keyof T>(event?: K, listener?: T[K]) => void;
  publish: <K extends keyof T>(event: K, ...args: Parameters<T[K]>) => Promise<void>;
};

注意事项

  • 异步执行:所有监听器都是异步执行的,使用 setTimeout(fn, 0) 实现

  • 执行顺序:监听器按订阅顺序执行,但因为是异步的,不能保证绝对的执行时机

  • 内存管理:长时间运行的应用需要及时清理不再使用的监听器

  • 错误隔离:单个监听器的错误不会影响其他监听器的执行

  • 重复订阅:系统会自动检测并警告重复的监听器订阅

许可证

MIT

贡献指南

欢迎提交 Issue 和 Pull Request!