Gathering detailed insights and metrics for @haelue/evt-bus
Gathering detailed insights and metrics for @haelue/evt-bus
Gathering detailed insights and metrics for @haelue/evt-bus
Gathering detailed insights and metrics for @haelue/evt-bus
Event bus with powerful features: type inferring, async emitter, propagation stop, handler sorting, group off, etc.
npm install @haelue/evt-bus
Typescript
Module System
Min. Node Version
Node Version
NPM Version
TypeScript (79.6%)
JavaScript (20.14%)
Shell (0.26%)
Total Downloads
19
Last Day
1
Last Week
4
Last Month
19
Last Year
19
1 Stars
6 Commits
1 Watching
1 Branches
1 Contributors
Latest Version
2.0.3
Package Id
@haelue/evt-bus@2.0.3
Unpacked Size
153.64 kB
Size
31.12 kB
File Count
38
NPM Version
8.5.5
Node Version
16.15.0
Publised On
19 Nov 2024
Cumulative downloads
Total Downloads
Last day
0%
1
Compared to previous day
Last week
100%
4
Compared to previous week
Last month
0%
19
Compared to previous month
Last year
0%
19
Compared to previous year
language: English | 中文
An event bus tool with powerful features:
Step1: This project uses node and npm to install.
1$ npm install --save @haelue/evt-bus
Step2: Insert types in Global-Declare-File: src/global.d.ts (create one if non-exist)
1/** file: src/global.d.ts */ 2 3declare type EvtGroupName = import("@haelue/evt-bus").EvtGroupName; 4declare type EvtOrder = import("@haelue/evt-bus").EvtOrder; 5declare type EvtRepeatable = import("@haelue/evt-bus").EvtRepeatable; 6declare type EvtMessage = import("@haelue/evt-bus").EvtMessage;
Step3: Create a Channel-File: src/events/index.ts (OR anywhere)
1/** file: src/events/index.ts */ 2 3import { 4 EvtChannel, 5 EvtChannelName, 6 EvtOnMethod, 7 EvtOffMethod, 8 EvtOffAllMethod, 9 EvtOnCountMethod, 10 EvtEmitMethod, 11 EvtEmitAsyncMethod, 12 EvtWithExceptionHandlerMethod, 13 EvtChannelOptions, 14 evtDefaultOptions, 15} from "@haelue/evt-bus"; 16 17interface UserEvtChannel { 18 /** Add event-listenning */ 19 on: EvtOnMethod & EvtOnOffDictionary; 20 21 /** Remove event-listenning of same handler(if defined) & same group(if defined) & same order(if defined) */ 22 off: EvtOffMethod & EvtOnOffDictionary; 23 24 /** Remove all event-listenning of same group(if defined) & same order(if defined) */ 25 offAll: EvtOffAllMethod; 26 27 /** Emit event */ 28 emit: EvtEmitMethod & EvtEmitDictionary; 29 30 /** Emit event (async) */ 31 emitAsync: EvtEmitAsyncMethod & EvtEmitAsyncDictionary; 32 33 /** Count of event-listenning */ 34 onCount: EvtOnCountMethod & EvtOnCountDictionary; 35 36 /** Set exception-handler once for next emit */ 37 withExceptionHandler: EvtWithExceptionHandlerMethod< 38 EvtEmitDictionary, 39 EvtEmitAsyncDictionary 40 >; 41} 42 43export const channelCached: Record<EvtChannelName, any> = {}; 44 45/** Get an event-channel of options (caching). */ 46export default function evt( 47 options?: Partial<EvtChannelOptions>, 48): UserEvtChannel { 49 const name = options?.name ?? evtDefaultOptions.name; 50 return (channelCached[name] ??= new EvtChannel(options)); 51}
Tip: It can both use in Browser.js OR Node.js; With both esm, cjs OR umd.
Step4: Create an Event-Declare-File: src/events/evt.d.ts (OR anywhere, but ends with evt.d.ts / emit.d.ts)
1/** file: src/events/evt.d.ts */ 2 3declare interface EvtEmitDictionary { 4 /** example emitter with type infer */ 5 fooTrigger(bar: { id: string; score: number; time: Date }): boolean; 6}
Tip: Return type must be: boolean.
Step5: Run command below: (recommand insert into package.json)
1$ npx evt-autogen
Other declares will generate in your Event-Declare-File (Step4). (see what happens in src/events/evt.d.ts)
Step6: Use the event "fooTrigger":
1/** file: path/to/your/code.ts */ 2 3import evt from "src/events"; 4const { emit, on, off } = evt(); 5 6on.fooTrigger((e, bar: { id: string; score: number; time: Date }) => { 7 console.log(`event received! ${JSON.stringify(bar)}`); 8}); 9 10emit.fooTrigger({ id: "foo", score: 1, time: new Date() }); 11 12// console print: 13// event received! {"id":"foo","score":1,"time":"2024-11-01T06:48:50.865Z"} 14 15off.fooTrigger(); 16 17emit.fooTrigger({ id: "foo2", score: 2, time: new Date() }); 18 19// console print: 20// [nothing as expected]
Tip:
evt()
provides the same cached instance in different file.
The usage mode of evt-bus can be very flexible.
You can create many Event-Declare-File (Step4) in different modules, evt-autogen scan path ./src recursive.
You can use -p to change scan path.
1$ npx evt-autogen -P [path/to/declare/files/root] 2# "-p -path -PATH" is also ok
You can use export interface
instead of declare interface
in Event-Declare-File (Step4), and make the filename ends with evt.ts / emit.ts (without ".d."), and import symbols in Channel-File (Step3).
The first "e" argument in on-handler is like: { message: "fooTrigger", cancel: false }
, you can use e.cancel = true
to stop event propagation. But if you don't need this feature, and hate the first "e" argument, directions below would help:
1/** file: src/events/index.ts */ 2 3import { 4--- EvtChannel, 5+++ EvtChannelSimple as EvtChannel, 6... 7} from "@haelue/evt-bus"
1$ npx evt-autogen -S 2# "-s -simple -SIMPLE" is also ok
1import evt from "src/events"; 2const { emit, on, off } = evt({ 3 // each option below is ommitable 4 name: "channel-1", // default "#" 5 defaultGroup: "group-1", // default "*" 6 defaultOrder: -1, // default 0 7 defaultRepeatable: true, // default false 8 defaultExceptionHandler: console.log, // default console.error 9});
1import evt from "src/events"; 2const { emitAsync, on } = evt(); 3 4on.fooTrigger(async (e, bar: { id: string; score: number; time: Date }) => { 5 console.log(`event received! ${JSON.stringify(bar)}`); 6}); 7 8await emitAsync.fooTrigger({ id: "foo", score: 1, time: new Date() });
1import evt from "src/events"; 2const { emit, on } = evt(); 3 4let changeFlag = false; 5on.fooTrigger((e, bar: { id: string; score: number; time: Date }) => { 6 e.cancel = true; 7}); 8on.fooTrigger((e, bar: { id: string; score: number; time: Date }) => { 9 changeFlag = true; 10}); 11 12const result = emit.fooTrigger({ id: "foo", score: 1, time: new Date() }); 13console.log(`result: ${result}, flag changed: ${changeFlag}`); 14 15// console print: 16// result: false, flag changed: false
The default sort-order is 0, you can change it in channel-building, OR in on-method.
1import evt from "src/events"; 2const { emit, on } = evt({ defaultOrder: 2 }); 3 4on.fooTrigger((e, bar: { id: string; score: number; time: Date }) => { 5 console.log(`event received: Order 2 (default)}`); 6}); 7on.fooTrigger( 8 (e, bar: { id: string; score: number; time: Date }) => { 9 console.log(`event received: Order 3}`); 10 }, 11 undefined, 12 3, 13); 14on.fooTrigger( 15 (e, bar: { id: string; score: number; time: Date }) => { 16 console.log(`event received: Order 1`); 17 }, 18 undefined, 19 1, 20); 21 22emit.fooTrigger({ id: "foo", score: 1, time: new Date() }); 23 24// console print: 25// event received: Order 3 26// event received: Order 2 (default) 27// event received: Order 1
The default group name is *, you can change it in channel-building, OR in on-method.
1import evt from "src/events"; 2const { on, offAll } = evt({ defaultGroup: "group-1" }); 3 4on.fooTrigger( 5 (e, bar: { id: string; score: number; time: Date }) => {}, 6 "group-2", 7); 8on.eventBar((e, bar: string, tick: number) => {}, "group-2"); 9 10offAll("group-2");
The default setting is avoid-repeat, you can change to allow-repeat in channel-building, OR in on-method.
1import evt from "src/events"; 2const { emit, on } = evt({ defaultRepeatable: true }); 3 4const handler1 = (e, bar: { id: string; score: number; time: Date }) => { 5 console.log(`event received in handler1`); 6}; 7on.fooTrigger(handler1); 8on.fooTrigger(handler1); 9on.fooTrigger(handler1); 10 11const handler2 = (e, bar: { id: string; score: number; time: Date }) => { 12 console.log(`event received in handler2`); 13}; 14on.fooTrigger(handler2, undefined, undefined, false); 15on.fooTrigger(handler2, undefined, undefined, false); 16on.fooTrigger(handler2, undefined, undefined, false); 17 18emit.fooTrigger({ id: "foo", score: 1, time: new Date() }); 19 20// console print: 21// event received in handler1 22// event received in handler1 23// event received in handler1 24// event received in handler2
Tip: Each arrow-function creates different instance, which is not repeat
The default handler is console.error, you can change it in channel-building, OR using withExceptionHandler-method.
1import evt from "src/events"; 2const { withExceptionHandler, emit, on } = evt({ 3 defaultExceptionHandler: () => console.log("Handle error throws"), 4}); 5 6on.fooTrigger((e, bar: { id: string; score: number; time: Date }) => { 7 throw new Error("Specified error"); 8}); 9 10emit.fooTrigger({ id: "foo", score: 1, time: new Date() }); 11 12// console print: 13// Handle error throws 14 15const avoidErrorLog = () => {}; 16withExceptionHandler(avoidErrorLog).emit.fooTrigger({ 17 id: "foo", 18 score: 1, 19 time: new Date(), 20}); 21 22// console print: 23// [nothing as expected]
Tip: If event-handler is async, use async emitter.
String-message is also supported like a typical event bus.
1import evt from "src/events"; 2const { emit, on, off } = evt(); 3 4on("fooTrigger", (e, bar: { id: string; score: number; time: Date }) => { 5 console.log(`event received! ${JSON.stringify(bar)}`); 6}); 7 8emit("fooTrigger", { id: "foo", score: 1, time: new Date() }); 9 10off("fooTrigger");
Tip: And it is also compatible to declare-type usage.
Advanced details that you may not use, but needs to be mentioned.
Use onCount-method to count subscribe listeners.
1import evt from "src/events"; 2const { on, off, onCount } = evt(); 3 4on.fooTrigger((e, bar: { id: string; score: number; time: Date }) => { 5 console.log(`event received! ${JSON.stringify(bar)}`); 6}); 7on.fooTrigger((e, bar: { id: string; score: number; time: Date }) => { 8 console.log(`event received! ${JSON.stringify(bar)}`); 9}); 10 11console.log("fooTrigger event subscribe count: ", onCount.fooTrigger()); 12 13// console print: 14// fooTrigger event subscribe count: 2 15 16off.fooTrigger(); 17 18console.log("fooTrigger event subscribe count: ", onCount.fooTrigger()); 19 20// console print: 21// fooTrigger event subscribe count: 0
See the declares of methods: on, off, offAll, onCount:
1interface onMethods { 2 fooTrigger(handler, groupId?, sortOrder?, repeatable?): void; 3} 4interface offMethods { 5 fooTrigger(handler?, groupId?, sortOrder?): void; 6} 7interface offAllMethod { 8 (groupId?, sortOrder?): void; 9} 10interface onCountMethods { 11 fooTrigger(handler?, groupId?, sortOrder?): number; 12}
In on-method, if you ommit any parameter OR put undefined
, the parameter will get default value.
But in off / offAll / onCount -method, if you ommit any parameter OR put undefined
, it means this "Parameter-Match-Condition" will be ignored while searching listeners.
In a badly structed project, tons of events may interweaving here and there. A debug tool is designed to analyze them. Example of vue3 web project as belows:
1/** file: main.ts */ 2 3import { nextTick } from "vue"; 4import { loadEvtDebug } from "@haelue/evt-bus"; 5loadEvtDebug(false, nextTick, ["mouseMoving", "keyboardPressing"]);
Run the web project, open the browser console, input evtDebug()
and see what outputs.
No vulnerabilities found.
No security vulnerabilities found.