Giter Club home page Giter Club logo

tiny-emitter's Introduction

tiny-emitter

A tiny (less than 1k) event emitter library.

Install

npm

npm install tiny-emitter --save

Usage

var Emitter = require('tiny-emitter');
var emitter = new Emitter();

emitter.on('some-event', function (arg1, arg2, arg3) {
 //
});

emitter.emit('some-event', 'arg1 value', 'arg2 value', 'arg3 value');

Alternatively, you can skip the initialization step by requiring tiny-emitter/instance instead. This pulls in an already initialized emitter.

var emitter = require('tiny-emitter/instance');

emitter.on('some-event', function (arg1, arg2, arg3) {
 //
});

emitter.emit('some-event', 'arg1 value', 'arg2 value', 'arg3 value');

Instance Methods

on(event, callback[, context])

Subscribe to an event

  • event - the name of the event to subscribe to
  • callback - the function to call when event is emitted
  • context - (OPTIONAL) - the context to bind the event callback to

once(event, callback[, context])

Subscribe to an event only once

  • event - the name of the event to subscribe to
  • callback - the function to call when event is emitted
  • context - (OPTIONAL) - the context to bind the event callback to

off(event[, callback])

Unsubscribe from an event or all events. If no callback is provided, it unsubscribes you from all events.

  • event - the name of the event to unsubscribe from
  • callback - the function used when binding to the event

emit(event[, arguments...])

Trigger a named event

  • event - the event name to emit
  • arguments... - any number of arguments to pass to the event subscribers

Test and Build

Build (Tests, Browserifies, and minifies)

npm install
npm run build

Test

npm install
npm test

License

MIT

tiny-emitter's People

Contributors

chocolateboy avatar dan503 avatar endel avatar lmk123 avatar madarauchiha avatar scottcorgan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tiny-emitter's Issues

TinyEmitter can't be imported in TypeScript with the normal module import syntax

Code:

import * as TinyEmitter from 'tiny-emitter';

Expected:
TinyEmitter available and no compilation errors thrown

Actual:
TypeScript complains about module 'tiny-emitter' resolves to a non-module entity and cannot be imported using this construct


Classes can't be exported with the export = Something syntax and be imported with the import * as syntax.

They must be imported with import TinyEmitter = require('tiny-emitter'), which will also fail compilation if you're not targeting commonjs modules.

While the correct solution is likely to move to ES2015 modules in the package's source (and have the transpiler deal with it), I propose we add either a exports.default = TinyEmitter or exports.TinyEmitter = TinyEmitter and change the .d.ts file, so that we may import TinyEmitter in the standard way.

Create events collection dynamically

This would be a really useful base for inheritance, but by creating the collection this.e = {} in the constructor, it would be necessary to call Emitter.call(this); inside any subclass.

The various emitter methods could do something like var e = this.e || (this.e = {}); which would make inheritance trivial.

When the same callback has been added to the same event more than once, off() skips checks for the next listener

evts.splice(i, 1) is called using the index of the the copied array, which modifies the indices of the original array, and the next iteration skips the listener after the one which was removed.

To solve this, you can simply iterate over the original array using a for loop and decrement the iterator whenever you splice, also taking care to either check evts.length on every iteration or to decrement your length variable len as well.

You could also use the same approach as Backbone, which creates a new array and only keeps the listeners that are not being removed, then overwrites the previous array.

Annoying to use with ES6 imports and Browserify

The expected way to import modules with ES6 and browserify is this:

import emitter from 'tiny-emitter';

emitter.on('event', ()=>{ /* functionality */ });

However there is an extra step involved in order to import tiny emitter into a project in a way that lets modules talk to one another across different files due to tiny-emitter exporting an uncalled javascript class.

//local emitter.js file

import Emitter from 'tiny-emitter';

export default new Emitter();
// module js file

import emiter from './path/to/emitter.js';

emitter.on('event', ()=>{ /* functionality*/ });

As you can see it feels like an unnecessary extra step and a tiny extra file in the file system.

What I would propose is having tiny emitter export an already called emitter rather than an uncalled class.

So instead of this as the export command (which is what you pretty much have at the moment):

export default Emitter;

You would have this:

const emitter = new Emitter();
export default emitter;
export { emitter, Emitter };

This would be a breaking change but I think it would be worth it for the ease of use it brings to your users.

The second export allows people to still alter/extend the class itself if they wish. The vast majority of the time, you only want to import the already called emitter though and this set up allows for that more easily.

I would have done the change myself in a pull request but I don't know typscript well enough to make the necessary edits.

Multiple on events only first one firing

emitter.on('some-event', function () {
 console.log(1)
});
 
emitter.on('some-event', function () {
 console.log(2)
});
emitter.emit('some-event');

Results in only 1 instead of 1 2

off doesn't unbind once

I'm surprised this hasn't been discovered before as it's a major bug.

var assert = require('assert');
var Emitter = require('tiny-emitter');
var emitter = new Emitter();

var pleaseNeverCallMe = assert.bind(assert, false, 'You called me, didn\'t you?');
var pleaseNeverCallMeEvenOnce = assert.bind(assert, false, 'You called me, didn\'t you?');

emitter.on('some-event', pleaseNeverCallMe);
emitter.once('some-event', pleaseNeverCallMeEvenOnce);

emitter.off('some-event', pleaseNeverCallMe);
emitter.off('some-event', pleaseNeverCallMeEvenOnce);

emitter.emit('some-event');

The cause is simple: you use on internally with a wrapper function, not the original one.

I just randomly chose another module and checked how they do it. E.g. little-emitter. They add a property to the wrapper function which references the original one.

https://github.com/Alex1990/little-emitter/blob/master/emitter.js#L58
https://github.com/Alex1990/little-emitter/blob/master/emitter.js#L78

Emitter expression is not constructable

I'm a starter and I hope you beg my pardon cuz maybe I'm looking a little stupid for you, but, I can't solve that problem.
I created a util called bus, and I am trying to use the Emitter with TS :

import Emitter from "tiny-emitter";

export default new Emitter();

but I received that error:

This expression is not constructable.
  Type 'typeof import("C:/projeto Controle Financeiro/wa-controle-financeiro/node_modules/tiny-emitter/index")' has no construct signatures.

I hope you can help me.

Listner event with regex

Hello, I would like to suggest that we could make a listener by regex. With that, I can make it more dynamic and be able to create multiple listeners in just one;

How can you create special characters like "#" and or "+" and replace them with regex; Iqual Style an MQTT or RabbitMQ topic

Ex:

Topics I need:

Topic: '/ org / 1 / dev / 1'
Topic: '/ org / 1 / dev / 2'

Topic :: '/ org / 2 / dev / 1'
Topic: '/ org / 2 / dev / 2'

Just use regex and get N topics. Bellow this is just a simple example

image

const myMap = new Map();

// Set data of the organization 1
myMap.set('/org/1/device/1');
myMap.set('/org/1/device/2');

// Set data of the organization 2
myMap.set('/org/2/device/1');
myMap.set('/org/2/device/2');

//
// First test: Get all device of the organization 1
//

const getAllDevicesOrg1 = new RegExp('\/org\/1(([\/])(\w*))*');
const resultOne = [...myMap.keys()].filter(item => getAllDevicesOrg1.test(item));
console.log(resultOne);
// Output [ '/org/1/device/1', '/org/1/device/2' ]


//
// Second test: Get all device all organizations
//

const getAllDevices = new RegExp('\/org(([\/])(\w*))*');
const resultTwo = [...myMap.keys()].filter(item => getAllDevices.test(item));
console.log(resultTwo);
// Output [
//   '/org/1/device/1',
//   '/org/1/device/2',
//   '/org/2/device/1',
//   '/org/2/device/2'
// ]

Proposal for version 3.0

After thinking about the implementation details and the API surface area I'd like to make the following proposal for changing this package and making another package based of this package:

tiny-emitter

This would be rewritten in the es2015 class syntax with the following API:

class Emitter {
  on() {}
  off() {}
  emit() {}
}

This removes the once() function in favor of a smaller file API surface area. once() can be emulated easily enough. Also, this makes the package way smaller as most people code bases have a transpilation step anyway. We could also provide a transpiled and minified file in the dist directory.

tiny-emitter-extended

Then, we would create a new package that extends tiny-emitter called tiny-emitter-extended with the follow API:

class EmitterExtended extends Emitter {
  once() {}
  onAll() {}
  offAll() {}
  onceAll() {}
  emitAsync() {}
}

This is a convenience package that adds a little bit more wait.

Notable:

  • once() moved here for convenience
  • onAll() or on('*') would add a wildcard listener for every event
  • offAll() or `off('*') would unsubscribe from every event
  • onceAll() or once('*') would subscribe to all events once
  • emitAsync() would emit the event on next animation frame for convenience of when you define your listeners

How to respond

Please respond with ideas, changes, recommendations, and dislikes (hopefully with solutions) so that I know if we should move forward with these changes, or not ๐Ÿ‘

Add support for ES6 module import

Currently I'm developing several webcomponents using Polymer 3 and LitElement. Both of them rely on ES6 imports and leverage on the browser ES6 modules import capabilities.

For one of my components I have a dependency on a lib that depends on tiny-emitter. I would need tiny-emitter to be available also as an ES6 module.

I'm making a PR to propose it...

Don't use for (var i in evts) to iterate over arrays

This approach is inherently brittle if an enumerable property has been added to the array prototype:

Array.prototype.last = function() {
    return this.length && this[this.length-1] || null;
};

Yes, the above code is bad-practice (at least use Object.defineProperty to make it non-enumerable), but your library cannot be sure that arrays will not have been abused as such.

Use a for loop.

Feature: Add Persistent to Event

First, thank you for creating this Event Bus. It was easy to setup. Much appreciated.

Problem

If I send an event prior the on handler is setup, that event is lost by the time the on handle is setup; therefore, the event is not persistent.

It would be nice to have a way to indicate that the event being emitted is persistent.
In this way, if the on handler is set later, it will still receive the event.

Replicate

Create a Tabs project using Ionic + Vue3 with tiny-emitter
(Ionic have an example of this)

Create two tabs (or whatever number you want).

On tab 1, I select an image and send an event with the data of the image.

EventBus().emitter.emit("selectedImage", image); 

On tab 2, I have the event handler (consumer) on

const instance = getCurrentInstance();    
    EventBus().emitter.on("selectedImage", (image: Image) => {     
      if (instance){
        instance.data.image = image.webviewPath
      }
 })

I have tried in many places in the code such as beforeCreated, Created, beforeMount, mounted, setup, onMounted (inside setup), etc.

Nice to have

It would be nice to indicate that the event emitted should be persistent.
This would allow the consumption of the event the moment a on handler is set.

Implement inversion of control flavors of on(), once(), and off()

This might be outside of the goals of this library (tiny-emitter), but it would be great to see the IoC flavors of the methods:

  • on: listenTo
  • once: listenToOnce
  • off: stopListening

These are incredibly useful for ensuring that all event listeners are cleaned up. For instance, a parent class can call stopListening in its destruct method, ensuring that any event listener added by any child class goes away during destruction.

For further documentation, see the documentation for Backbone's Event mixin.

What do you think?

Make .on and .once return unsubscribe functions

What about changing the .on method to

    on: function (name, callback, ctx) {
    var self = this;
    var e = this.e || (this.e = {});

    (e[name] || (e[name] = [])).push({
      fn: callback,
      ctx: ctx
    });

    var offFunc = function()
    {
      return self.off(name, callback);
    }

    return offFunc;
  },

So we can have a better way to handle event unsubscribing

can I got all event name?

image
Can I got all event name like below?
const allEvent=emitter.off(); // emit();
console.log(allEvent.e)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.