@ collidor/ event
轻量级事件系统 有跨文本通信. 适合现代网络应用,工人,和分布式系统.
安装
npm install @collidor/event
核心特征
- 严格打字的基于类的事件系统
- 跨文本通讯( Window QQ 工人分页)
- 广播频道/共享工作者的内置支持
- 背景传播和中止控制器集成
基本用途
使用类继承
import { Event } from "@collidor/event";
class UserUpdate extends Event<{ id: string }> {}
class SystemAlert extends Event<string> {}
import { EventBus } from "@collidor/event";
const bus = new EventBus();
// Subscribe
bus.on(UserUpdate, (data) => {
console.log(`User ${data.id} updated`);
});
// Publish
bus.emit(new UserUpdate({ id: "123" }));
使用 createEvent (邦德勒/无害安全)
当捆绑用于生产时,JavaScript分解器常常会操纵类名(例如. class UserUpdate 变成 class a) (中文(简体) ). 自活动总线和频道以来PortChannel, (中文(简体) ), WindowCustomEventPort(b) 使用其构造器名称对事件进行路线和序列化, createEvent 提供了一种类型安全的方法来定义带有固定的,不可忽略的名称的事件 :
import { createEvent, EventBus } from "@collidor/event";
// Define event with explicit payload type and name: createEvent<PayloadType>("EventName")
export const UserUpdate = createEvent<{ id: string }>("UserUpdate");
// Void events (no arguments required):
export const UserLoggedOut = createEvent<void>("UserLoggedOut");
const bus = new EventBus();
bus.on(UserUpdate, (data) => {
console.log(`User ${data.id} updated`);
});
bus.on(UserLoggedOut, () => {
console.log("User logged out");
});
bus.emit(new UserUpdate({ id: "123" }));
bus.emit(new UserLoggedOut());
交叉连接模式
PortChannel 是主要导出通道, 它接受 MessagePortLike 端口,该端口
有个 postMessage 方法,并可以设置和使用 onmessage 属性召回。 这意味着
浏览器的 API 如 BroadcastChannel、 Worker 和 共享 Worker 默认工作 .
我的计划是稍后再加入适配器,这样其他的东西可以像端口一样表现,比如Websockets,WebRTC,Http+SEE和Datagrams.
PortChannel不会向没有发送消息的端口发送事件,首先告诉它有这样的事件的订阅者.
1. 广播频道(对台)
import { PortChannel, EventBus } from "@collidor/event";
const channel = new PortChannel();
const bus = new EventBus({ channel });
channel.addPort(new BroadcastChannel("app-channel"));
class TabMessage extends Event<string> {}
bus.emit(new TabMessage("Hello from Tab A!"));
import { PortChannel, EventBus } from "@collidor/event";
const channel = new PortChannel();
const bus = new EventBus({ channel });
channel.addPort(new BroadcastChannel("app-channel"));
bus.on(TabMessage, (msg) => {
console.log("Received:", msg); // "Hello from Tab A!"
});
2. 共享工人(多文本)
import { PortChannel, EventBus } from "@collidor/event";
const channel = new PortChannel();
const bus = new EventBus({ channel });
const worker = new SharedWorker("worker.js");
channel.addPort(worker.port);
class TaskEvent extends Event<{ id: string }> {}
bus.emit(new TaskEvent({ id: "shared-task" }));
import { PortChannel, EventBus } from "@collidor/event";
const channel = new PortChannel();
const bus = new EventBus({ channel });
// Handle new connections
self.onconnect = (event) => {
const port = event.ports[0];
channel.addPort(port);
};
self.start();
bus.on(TaskEvent, ({ id }) => {
console.log("Processing shared task:", id);
});
高级图案
背景宣传
const bus = new EventBus({
context: { requestId: "123" }
});
bus.on(DataEvent, (data, ctx) => {
console.log(ctx.requestId); // "123"
});
// Override per emission
bus.emit(new DataEvent(), { requestId: "temp" });
API 概览
事件窗口
on(event, handler, signal?)off(event, handler)emit(event, context?)emitByName(name, data, context?)
端口通道
addPort(port)removePort(port)publish(event)subscribe(name, callback)unsubscribe(name, callback)
PortChannel 序列图
sequenceDiagram
participant S as Server PortChannel
participant MP as MessagePort
participant C as Client PortChannel
%% Server adds a MessagePort (acts as connecting port)
S->>MP: addPort(port)
Note over S,MP: Server attaches MessagePort
%% MessagePort forwards startEvent to the Client
MP->>C: onmessage({type: "startEvent"})
Note over C: Client receives startEvent and sets up message handlers
%% Client subscribes to "TestEvent"
C->>MP: postMessage({type:"subscribeEvent", name:"TestEvent"})
Note over C: Client tells that it has a subscription for "TestEvent"
%% MessagePort delivers subscribeEvent to Server
MP->>S: onmessage({type:"subscribeEvent", name:"TestEvent"})
Note over S: Server calls addPortSubscription("TestEvent")
%% If the Server had buffered events for "TestEvent", flush them:
alt Buffered events exist for "TestEvent"
S->>MP: postMessage(buffered dataEvent for "TestEvent")
MP->>C: onmessage(buffered dataEvent for "TestEvent")
else
Note over S: No buffered events to flush
end
%% Now, the Server publishes a new event "TestEvent"
S->>S: publish("TestEvent", data)
alt Subscriber exists
S->>MP: postMessage({type:"dataEvent", name:"TestEvent", data})
MP->>C: onmessage({type:"dataEvent", name:"TestEvent", data})
Note over C: Client processes the dataEvent
else
S->>S: Buffer event "TestEvent" with timeout
Note over S: Event buffered until a subscriber appears
end
发展
# Install dependencies
npm install
# Run tests (requires Deno)
npm test
# Build project
npm run build