{"id":17920570,"url":"https://github.com/nem035/psub","last_synced_at":"2025-04-03T11:13:10.249Z","repository":{"id":65477319,"uuid":"78896183","full_name":"nem035/psub","owner":"nem035","description":"Publish/Subscribe in JavaScript.","archived":false,"fork":false,"pushed_at":"2017-02-08T03:14:36.000Z","size":145,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-10T07:17:48.871Z","etag":null,"topics":["event-management","javascript","javascript-library","psub","publishing","subscription"],"latest_commit_sha":null,"homepage":"https://github.com/nem035/psub","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nem035.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-01-13T23:55:01.000Z","updated_at":"2022-11-20T07:35:55.000Z","dependencies_parsed_at":"2023-01-25T15:30:13.423Z","dependency_job_id":null,"html_url":"https://github.com/nem035/psub","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nem035%2Fpsub","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nem035%2Fpsub/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nem035%2Fpsub/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nem035%2Fpsub/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nem035","download_url":"https://codeload.github.com/nem035/psub/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246989747,"owners_count":20865331,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["event-management","javascript","javascript-library","psub","publishing","subscription"],"created_at":"2024-10-28T20:26:10.873Z","updated_at":"2025-04-03T11:13:10.229Z","avatar_url":"https://github.com/nem035.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PSub [![Build Status](https://img.shields.io/travis/nem035/psub/master.svg?style=flat-square)](https://travis-ci.org/nem035/psub) [![Codecov branch](https://img.shields.io/codecov/c/github/nem035/psub/master.svg?style=flat-square)]() [![npm](https://img.shields.io/npm/v/psub.svg?style=flat-square)]() [![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg?style=flat-square)](http://commitizen.github.io/cz-cli/)\n\nImplementation of the [Publish/Subscribe](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern) design pattern using ES6 features. Think [Event Emitter](https://en.wikipedia.org/wiki/Event-driven_architecture).\n\n## What is Publish/Subscribe?\n\nIt is an event system that allows us to define application specific events which can serve as triggers for message passing between various parts of an application. The main idea here is to avoid dependencies and promote [loose coupling](https://en.wikipedia.org/wiki/Loose_coupling). Rather than single objects calling on the methods of other objects directly, they instead subscribe to a specific topic (event) and are notified when it occurs.\n\n## Features\n\n- ES6 [Symbols](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol) as subscription tokens (always unique)\n- Constant O(1) subscribe/unsubscribe time ([How It Works](#HowItWorks))\n- Wildcard publish to all listeners using the `'*'` topic\n- Asynchronous publish with [microtasks](https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/)\n- Method names we're all used to (`subscribe` === `on`, `publish` === `emit`, `unsubscribe` === `off`)\n- No dependencies\n- Small (~800b gzipped and compressed)\n\n## Example\n\n### [CodePen Playground](http://codepen.io/nem035/pen/NdLjMq?editors=0010)\n\n### Extending\n\n```js\n// emitter that logs any publish events\nimport PSub from 'psub';\n\nclass PSubLogger extends PSub {\n  constructor() {\n    super();\n  }\n\n  publish(evt, ...args) {\n    console.log(`publish (${evt}): ${args}`);\n    super.publish(evt, ...args);\n  }\n}\n```\n\n### Using (Node)\n\n```js\nimport http from 'http';\nimport PSub from 'psub';\n\nconst ps = new PSub();\n// can also use ps.on\nps.subscribe('request', ({ method, url }) =\u003e {\n  console.log(`${method}: ${url}`);\n});\n\nhttp.createServer((req, res) =\u003e {\n  // can also use ps.emit\n  ps.publish('request', req);\n  res.end('Works!');\n}).listen(1337, '127.0.0.1');\n```\n\n### Using (Browser) - [Code Pen Example](http://codepen.io/nem035/pen/YNOVwv)\n\n```js\nimport PSub from 'psub';\n\nconst ps = new PSub();\nps.subscribe('email/inbox', ({\n  subject,\n  body\n}) =\u003e {\n  new Notification(`Sent: ${subject}`, {\n    body\n  });\n});\n\ndocument\n  .querySelector('#send')\n  .addEventListener('click', () =\u003e {\n    const form = new FormData(document.getElementById('email-form'));\n    fetch('/login', {\n      method: 'POST',\n      body: form\n    }).then((response) =\u003e {\n      ps.publish('email/inbox', response);\n    });\n  });\n```\n\n## CommonJS\n\n```js\n// extract the default export\nconst { PSub } = require('psub');\n\nconst ps = new PSub();\n// ...\n```\n\n## Browser Script\n\nAdd the [code](https://unpkg.com/psub@latest/dist/index.umd.js) as a script or use the [unpkg](https://unpkg.com) cdn\n```html\n\u003cscript src=\"https://unpkg.com/psub@latest/dist/index.umd.js\"\u003e\u003c/script\u003e\n```\n```js\n// extract the default export\nconst { PSub } = window.PSub;\n\nconst ps = new PSub();\n// ...\n```\n\n## Installation\n\n- yarn\n```bash\nyarn add psub\n```\n\n- npm\n```bash\nnpm i psub\n```\n\n## API\n\n\u003ca name=\"PSub\"\u003e\u003c/a\u003e\n\n## PSub\nClass representing a PSub object\n\n**Kind**: global class\n\n* [PSub](#PSub)\n    * [new PSub()](#new_PSub_new)\n    * [.subscribe(topic, handler)](#PSub+subscribe) ⇒ \u003ccode\u003eSymbol\u003c/code\u003e\n    * [.publish(topic, ...args)](#PSub+publish)\n    * [.unsubscribe(symbol)](#PSub+unsubscribe) ⇒ \u003ccode\u003eBoolean\u003c/code\u003e\n\n\u003ca name=\"new_PSub_new\"\u003e\u003c/a\u003e\n\n### new PSub()\nCreate a PSub instance.\n\n\u003ca name=\"PSub+subscribe\"\u003e\u003c/a\u003e\n\n### pSub.subscribe(topic, handler) ⇒ \u003ccode\u003eSymbol\u003c/code\u003e\nSubscribes the given handler for the given topic.\n\n**Kind**: instance method of \u003ccode\u003e[PSub](#PSub)\u003c/code\u003e\u003cbr /\u003e\n**Alias**: `on`\u003cbr /\u003e\n**Returns**: \u003ccode\u003eSymbol\u003c/code\u003e - Symbol that can be used to unsubscribe this subscription\n\n| Param | Type | Description |\n| --- | --- | --- |\n| topic | \u003ccode\u003eString\u003c/code\u003e | Topic name for which to subscribe the given handler |\n| handler | \u003ccode\u003efunction\u003c/code\u003e | Function to call when given topic is published |\n\n**Example**\n```js\n// subscribe for the topic \"notifications\"\n// call onNotification when a message arrives\nconst subscription = psub.subscribe(\n  'notifications', // topic name\n  onNotification,  // callback\n);\n```\n\u003ca name=\"PSub+publish\"\u003e\u003c/a\u003e\n\n### pSub.publish(topic, ...args)\nMethod to publish data to all subscribers for the given topic.\n\n**Kind**: instance method of \u003ccode\u003e[PSub](#PSub)\u003c/code\u003e\u003cbr /\u003e\n**Alias**: `emit`\u003cbr /\u003e\n\n| Param | Type | Description |\n| --- | --- | --- |\n| topic | \u003ccode\u003eString\u003c/code\u003e | cubscription topic |\n| ...args | \u003ccode\u003eArray\u003c/code\u003e | arguments to send to all subscribers for this topic |\n\n**Example**\n```js\n// publish an object to anybody listening\n// to the topic 'message/channel'\npsub.publish('message/channel', {\n  id: 1,\n  content: 'PSub is cool!'\n})\n```\n\u003ca name=\"PSub+unsubscribe\"\u003e\u003c/a\u003e\n\n### pSub.unsubscribe(symbol) ⇒ \u003ccode\u003eBoolean\u003c/code\u003e\nCancel a subscription using the subscription symbol\n\n**Kind**: instance method of \u003ccode\u003e[PSub](#PSub)\u003c/code\u003e\u003cbr /\u003e\n**Alias**: `off`\u003cbr /\u003e\n**Returns**: \u003ccode\u003eBoolean\u003c/code\u003e - true if subscription was cancelled, false otherwise\n\n| Param | Type | Description |\n| --- | --- | --- |\n| symbol | \u003ccode\u003eSymbol\u003c/code\u003e | subscription Symbol obtained when subscribing |\n\n**Example**\n```js\n// unsubscribe using the subscription symbol\n// obtained when you subscribed\nconst didUnsubscribe = psub.unsubscribe(subscriptionSymbol);\n```\n\n## \u003ca name=\"HowItWorks\"\u003eHow it works\u003c/a\u003e\n\nThe PSub class internally maintains two [maps](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map).\n\n1. `Map\u003ctopic,subscriptionsList\u003e`\n2. `Map\u003csymbol,subscriptionLocation\u003e`\n\n- Subscribing\n\n  When `ps.subscribe(topic, handler)` is called, PSub looks up the list of existing subscriptions from `Map\u003ctopic,subscriptionsList\u003e` and appends the new subscription handler to the obtained list.\n  Then it creates a new Symbol to represent this subscription and creates a subscription location POJO of the form `{ topic: subscriptionTopic, index: positionInSubscriptionsArray }`, adding them to `Map\u003csymbol,subscriptionLocation\u003e`. Finally it returns the created Symbol.\n\n- Publishing\n\n  When `ps.publish(topic)` is called, PSub looks up the list of existing subscriptions from `Map\u003ctopic,subscriptionsList\u003e` and invokes their handlers, each in its own [microtask](https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/), passing along any provided arguments.\n\n- Unsubscribing\n\n  When `ps.unsubscribe(symbol)` is called, PSub uses this symbol to obtain a subscription location from `Map\u003csymbol,subscriptionLocation\u003e`. It then extracts the topic and position for this subscription from the obtained subscription location and removes the subscription from `Map\u003ctopic,subscriptionsList\u003e`. Finally it does some necessary cleanup and return `true` to signal success.\n\n## Licence\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnem035%2Fpsub","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnem035%2Fpsub","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnem035%2Fpsub/lists"}