Show HN:163 字节的 JavaScript PubSub 实现
文章介绍了一个仅有163字节的 JavaScript PubSub 实现,名为 `pico-pubsub`。该库旨在提供尽可能小的 PubSub 功能,且无依赖。文章对比了其他库,如 `nano-pubsub` 和 `tiny-pubsub`,强调了 `pico-pubsub` 的代码体积优势。文章提供了源码、使用示例和问题排查说明,并展示了如何验证代码体积。最后,作者鼓励用户提出优化建议。
pico-pubsub
尽可能小的 PubSub 库。零依赖。149 字节。
之前我写过这篇文章。但我意识到...为什么不直接发布代码呢?
比竞争对手更小。
nano-pubsub(https://github.com/bjoerge/nano-pubsub)tiny-pubusb(https://github.com/LukeWood/tiny-pubsub)
构建时考虑了 JS13K 游戏。比如 cred,不幸的是,它很快就需要减肥了,现在几乎有 25KB 了。
如果你有任何可以减少哪怕一个字节的想法,请分享。创建一个 issue!我不介意。
源码
这是完整的源码 (index.js):
let t = new EventTarget();
sub = (e, c) => (t.addEventListener(e, c), () => t.removeEventListener(e, c));
pub = (n, d) => t.dispatchEvent(new CustomEvent(n, { detail: d }));
用法
npm install pico-pubsub
import "pico-pubsub"
const unsub = sub('jump', function (anything) {
console.log("someone jumped - " + anything.detail)
});
pub('jump', "a_user_id")
>> "someone jumped - a_user_id"
unsub()
pub('jump', "another_user_id")
>> Nothing happens now
问题排查
- 将来可能会添加 TS 支持。目前,你可以使用以下代码片段。
declare global {
function pub(event: string, data: any): VoidFunction;
function sub(event: string, callback: (data: CustomEvent) => void): void;
}
- 如果你有导出问题,只需复制粘贴并更改导出类型。
验证
以下命令将生成一个 149b 文件:
npx esbuild index.js --bundle --minify --format=esm --outfile=bundle.js
竞争对手
排名第二的是 nano-pubsub,它缩小到了令人印象深刻的 194b... 相当不错!只大了 ~30%。
/**
* @public
*/
export interface Subscriber<Event> {
(event: Event): void;
}
/**
* @public
*/
export interface PubSub<Message> {
publish: (message: Message) => void;
subscribe: (subscriber: Subscriber<Message>) => () => void;
}
/**
* @public
*/
export default function createPubSub<Message = void>(): PubSub<Message> {
const subscribers: { [id: string]: Subscriber<Message> } =
Object.create(null);
let nextId = 0;
function subscribe(subscriber: Subscriber<Message>) {
const id = nextId++;
subscribers[id] = subscriber;
return function unsubscribe() {
delete subscribers[id];
};
}
function publish(event: Message) {
for (const id in subscribers) {
subscribers[id](event);
}
}
return {
publish,
subscribe,
};
}
排名第三的是 tiny-pubsub,它引入了一个非关键函数,以及一个处理取消订阅的额外函数!太痛苦了!它达到了惊人的 401b,是 nano-pubsub 的两倍多!
let subscriptions = Object.create(null);
function subscribe(evt, func) {
if (typeof func !== "function") {
throw "Subscribers must be functions";
}
const oldSubscriptions = subscriptions[evt] || [];
oldSubscriptions.push(func);
subscriptions[evt] = oldSubscriptions;
}
function publish(evt) {
let args = Array.prototype.slice.call(arguments, 1);
const subFunctions = subscriptions[evt] || [];
for (let i = 0; i < subFunctions.length; i++) {
subFunctions[i].apply(null, args);
}
}
function unsubscribe(evt, func) {
const oldSubscriptions = subscriptions[evt] || [];
const newSubscriptions = oldSubscriptions.filter((item) => item !== func);
subscriptions[evt] = newSubscriptions;
}
function cancel(evt) {
delete subscriptions[evt];
}
module.exports = { subscribe, publish, unsubscribe, cancel };
注意事项
如果你不想使用 window 对象,只需这样做,只是要知道这将花费你 7 个字节:
let t = new EventTarget();
export default {
s: (e, c) => (t.addEventListener(e, c), () => t.removeEventListener(e, c)),
p: (n, d) => t.dispatchEvent(new CustomEvent(n, { detail: d })),
};