Code Monkey home page Code Monkey logo

component-emitter's Introduction

component-emitter

Simple event emitter

Install

npm install component-emitter

Usage

As an Emitter instance:

import Emitter from 'component-emitter';

const emitter = new Emitter();

emitter.emit('๐Ÿฆ„');

As a mixin:

import Emitter from 'component-emitter';

const user = {name: 'tobi'};
Emitter(user);

user.emit('I am a user');

As a prototype mixin:

import Emitter from 'component-emitter';

Emitter(User.prototype);

API

new Emitter()

Create a new emitter.

Emitter(object)

Use it as a mixin. For example a plain object may become an emitter, or you may extend an existing prototype.

Emitter#on(event, listener)

Register an event handler that listens to a specified event.

Emitter#once(event, listener)

Register a one-time event handler for a specified event.

Emitter#off(event, listener)

Remove a specific event handler for a specified event.

Emitter#off(event)

Remove all event handlers for a specified event.

Emitter#off()

Remove all event handlers for all events.

Emitter#emit(event, ...arguments)

Emit an event, invoking all handlers registered for it.

Emitter#listeners(event)

Retrieve the event handlers registered for a specific event.

Emitter#listenerCount(event)

Get the count of listeners for a specific event.

Emitter#listenerCount()

Get the count of all event handlers in total.

Emitter#hasListeners(event)

Check if there are any handlers registered for a specific event.

Emitter#hasListeners()

Check if there are any handlers registered for any event.

FAQ

How does it differ from the Node.js EventEmitter?

It's simpler and more lightweight, and it works in any JavaScript environment, not just Node.js. It also provides mixin functionality to add event handling to existing objects without needing inheritance.

component-emitter's People

Contributors

bripkens avatar btd avatar forbeslindesay avatar gthb avatar haykokoryun avatar jonathanong avatar juliangruber avatar julienfouilhe avatar lusever avatar matthewmueller avatar michaelsanford avatar nkzawa avatar nulltask avatar rauchg avatar rschmukler avatar sindresorhus avatar stephenmathieson avatar strml avatar tj avatar tootallnate avatar vendethiel avatar yields 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

component-emitter's Issues

License please?

Thanks for this library!

Please would it be possible to add a message about the license in the README, or a separate LICENSE file, or even just specify it in the package.json?

I'd love to be able to use it in our open source application, but to go through our legal process I need to report on the licences of all our dependencies. (License Spelunker - https://github.com/mbrevoort/node-license-spelunker - is making it easy for those that have license notices, but this is one of the ones that showed up missing!)

Cheers,
Peter

Bower install is broken

Trying to run

bower install component/emitter

yell the following:

bower cloning git://github.com/component/emitter.git
bower cached git://github.com/component/emitter.git
bower fetching emitter
bower checking out emitter#1.0.1
bower warn Package emitter is still using the deprecated "component.json" file
bower copying /home/azureuser/.bower/cache/emitter/39f1c898e27cde1889acd0cb0fb69
915
bower cloning git://github.com/component/indexof
bower cached git://github.com/component/indexof
bower fetching component/indexof
bower checking out component/indexof#0.0.1
bower warn Package component/indexof is still using the deprecated "component.js
on" file
bower copying /home/azureuser/.bower/cache/component/indexof/227a1c729a8c07f9438
98d40ed249d18
bower error ENOENT, mkdir '/tmp/bower-component/indexof-69667dzi06o'

There were errors, here's a summary of them:
- component/indexof ENOENT, mkdir '/tmp/bower-component/indexof-69667dzi06o'

events.EventEmitter

Having a node compatible API would be awesome. Should I create a wrapper around component/emitter or shall I port node's emitter and component/emitter will be a wrapper around that?

Some way to count all listeners

I would like either a way to see what events have listeners, or count how many listeners are on an emitter altogether.

Happy to submit a PR, but it's an API change, so I thought I'd put it up for discussion.

Here's my current workaround (but requires accessing the private _callbacks property):

    Emitter.prototype.countListeners = function Emitter_countListeners(eventName) {
        var emitter = this
        if (eventName) {
            return emitter.listeners(eventName).length
        }
        var count = 0
        Object.keys(emitter._callbacks).forEach(function(keyname) {
            count += emitter.countListeners(keyname)
        })
        return count
    }

Update NPM version

The version on NPM is currently 1.0.1, while the version in this repository is 1.1.0. It would be nice to have an up-to-date version on NPM.

allow .off()

I.e. remove handlers for all events with arguments.length == 0

Node aliases disappeared?

I don't see any commits changing this or any version changes - somehow all of the node aliases disappeared and only .off exists - index.js looks like this after component install with version set to 0.0.6

/**
 * Expose `Emitter`.
 */

module.exports = Emitter;

/**
 * Initialize a new `Emitter`.
 * 
 * @api public
 */

function Emitter(obj) {
  if (obj) return mixin(obj);
};

/**
 * Mixin the emitter properties.
 *
 * @param {Object} obj
 * @return {Object}
 * @api private
 */

function mixin(obj) {
  for (var key in Emitter.prototype) {
    obj[key] = Emitter.prototype[key];
  }
  return obj;
}

/**
 * Listen on the given `event` with `fn`.
 *
 * @param {String} event
 * @param {Function} fn
 * @return {Emitter}
 * @api public
 */

Emitter.prototype.on = function(event, fn){
  this._callbacks = this._callbacks || {};
  (this._callbacks[event] = this._callbacks[event] || [])
    .push(fn);
  return this;
};

/**
 * Adds an `event` listener that will be invoked a single
 * time then automatically removed.
 *
 * @param {String} event
 * @param {Function} fn
 * @return {Emitter}
 * @api public
 */

Emitter.prototype.once = function(event, fn){
  var self = this;
  this._callbacks = this._callbacks || {};

  function on() {
    self.off(event, on);
    fn.apply(this, arguments);
  }

  fn._off = on;
  this.on(event, on);
  return this;
};

/**
 * Remove the given callback for `event` or all
 * registered callbacks.
 *
 * @param {String} event
 * @param {Function} fn
 * @return {Emitter}
 * @api public
 */

Emitter.prototype.off = function(event, fn){
  this._callbacks = this._callbacks || {};
  var callbacks = this._callbacks[event];
  if (!callbacks) return this;

  // remove all handlers
  if (1 == arguments.length) {
    delete this._callbacks[event];
    return this;
  }

  // remove specific handler
  var i = callbacks.indexOf(fn._off || fn);
  if (~i) callbacks.splice(i, 1);
  return this;
};

/**
 * Emit `event` with the given args.
 *
 * @param {String} event
 * @param {Mixed} ...
 * @return {Emitter} 
 */

Emitter.prototype.emit = function(event){
  this._callbacks = this._callbacks || {};
  var args = [].slice.call(arguments, 1)
    , callbacks = this._callbacks[event];

  if (callbacks) {
    callbacks = callbacks.slice(0);
    for (var i = 0, len = callbacks.length; i < len; ++i) {
      callbacks[i].apply(this, args);
    }
  }

  return this;
};

/**
 * Return array of callbacks for `event`.
 *
 * @param {String} event
 * @return {Array}
 * @api public
 */

Emitter.prototype.listeners = function(event){
  this._callbacks = this._callbacks || {};
  return this._callbacks[event] || [];
};

/**
 * Check if this emitter has `event` handlers.
 *
 * @param {String} event
 * @return {Boolean}
 * @api public
 */

Emitter.prototype.hasListeners = function(event){
  return !! this.listeners(event).length;
};

Any idea what might be going on?

bind

questionable, but still tempting to add, it's really not this library's concern however:

item.on('change complete', this.toggleCompleteClass, this);

is a bit nicer than:

item.on('change complete', this.toggleCompleteClass.bind(this));

which isn't x-browser anyway, but regardless it's still noise

dom like methods.

addEventListener, removeEventListener.

this should let you do stuff like:

function Node(emitter){
  this.events = events(emitter, this);
  this.events.bind('message');
}

Node.prototype.onmessage = function(){};

using component/events.

Doesn't respect addition/removal of listeners during dispatch.

Is this intentional/by design?
What is the rationale for slicing the listeners array before dispatching the event?

Example:

var obj = {}
Emitter(obj)

function a(){
   console.log('A')
   obj.off('x', b)
   obj.on('x', c)
}

function b(){
   console.log('B')
}

function c(){
   console.log('C')
}

obj.once('x', a)
obj.on('x', b)

obj.emit('x') // Logs: A, B. Expected: A, C

npm documentation is wrong

$ component install component/emitter should be $ npm install component-emitter.

Commenting as someone who has no idea what 'Component' is.

[Feature proposal] promise support

I'd like to know if you'd were open to add a simple "async/await" support in .emit to be able to respect order of execution within the emit loop:

- Emitter.prototype.emit = function(event){
+ Emitter.prototype.emit = async function(event){
  this._callbacks = this._callbacks || {};

  var args = new Array(arguments.length - 1)
    , callbacks = this._callbacks['$' + event];

  for (var i = 1; i < arguments.length; i++) {
    args[i - 1] = arguments[i];
  }

  if (callbacks) {
    callbacks = callbacks.slice(0);
    for (var i = 0, len = callbacks.length; i < len; ++i) {
-      callbacks[i].apply(this, args);
+      await callbacks[i].apply(this, args);
    }
  }

  return this;
};

It should not break anything for normal synchronous code, but would add that promises are respected if you were to have a usecase (such as mine):

on("someEvent", async () => {
  const data = await needToCallBackend()
  someExternalCallback(data)
})

on("someEvent", () => {
 // later listener added which should execute after, but will execute before since the 1st one has "async"
})

I hope this is clear enough and that it makes sense for you too.
If you have some guidance over how to solve my usecase without this proposal, i'm in for it too.

Thanks

Add ability to listen to multiple events

It would be great to add some ability to listen to multiple events e.g.

object.on("*", function(eventName, [arg1,arg2,...]) {});
object.on("namespace.*", function(eventName, [arg1,arg2,...]) {});
object.on("eventA eventB eventC", function(eventName, [arg1,arg2,...]) {});
object.on("eventA", function([arg1,arg2,...]) {});

So if a wildcard or multiple event names are used then the first argument to the function can be the event name otherwise not to maintain compatibility.

Alternatively just support:

object.on(function(eventName, [arg1,arg2,...]) {});

In my case I want to trim this code:

object.on("eventA", object.eventA);
object.on("eventB", object.eventB);
object.on("eventC", object.eventC);
object.on("eventD", object.eventD);
object.on("eventE", object.eventE);

To:

object.on("*", function() { object[arguments[0]].apply(object, arguments.slice(1)); });

Migration and maintaining

This repo seems pretty rusty. It is not maintained, nor is it updated regularly.
The work done in here is very cool, of great quality, and I think it is sad that even pushing to a branch, breaks the CI... Furthermore, although it is stable and widely used, there are many projects depending on this package.

I would like to migrate it to a new organization, and update it the CI. And replace the package on NPM by the new one. Of course, this repo should stay open, but mention the fact that it is deprecated.

Here are a few things I would like to take on at first:

  • fixing CI
  • adding more tests
  • adding checks on arguments passed to functions and otherwise throw human-friendly errors
  • etc.

Also, I am definitely open to anyone wanting to help ๐Ÿ˜Š

@tj @jonathanong @TooTallNate @juliangruber

Can't install component/emitter

When trying run component install component/emitter I get the error: component install component/emitter.

Does component not follow redirects?

context as third argument for on?

Example:

var agent = new emitter();

function View() {
  emitter(this);

  agent.on('error', this.error, this);
}

Would be very easy to implement. If no context is provided we use the emitters this as done now. So there are no breaks.

Would someone accept a PR on this?

mixin

I find it v useful to be able to mixin the emitter to an existing object

Warning: a promise was rejected with a non-error: [object Object]

Using FeathersJS only in the production environment after a successful login I get Warning: a promise was rejected with a non-error: [object Object].

I'm using bluebird, if I remove bluebird the failure is silent, I don't get errors or warnings, and it stops the execution of the current action. I don't know if it can be related to feathers or socket.io or component-emitter.

If you need to see my setup the app is: https://github.com/foxhound87/rfx-stack

Warning: a promise was rejected with a non-error: [object Object]
    at Socket.on (http://localhost:3000/build/bundle.js:49005:9)
    at Socket.Emitter.emit (http://localhost:3000/build/bundle.js:49073:21)
    at Socket.onevent (http://localhost:3000/build/bundle.js:48787:11)
    at Socket.onpacket (http://localhost:3000/build/bundle.js:48745:13)
    at Manager.<anonymous> (http://localhost:3000/build/bundle.js:37783:16)
    at Manager.Emitter.emit (http://localhost:3000/build/bundle.js:49073:21)
    at Manager.ondecoded (http://localhost:3000/build/bundle.js:48264:9)
    at Decoder.<anonymous> (http://localhost:3000/build/bundle.js:37783:16)
    at Decoder.Emitter.emit (http://localhost:3000/build/bundle.js:29390:21)
    at Decoder.add (http://localhost:3000/build/bundle.js:37350:13)
    at Manager.ondata (http://localhost:3000/build/bundle.js:48254:17)
    at Socket.<anonymous> (http://localhost:3000/build/bundle.js:37783:16)
From previous event:
    at authenticateSocket (http://localhost:3000/build/bundle.js:116466:11)
    at http://localhost:3000/build/bundle.js:116351:49
From previous event:
    at http://localhost:3000/build/bundle.js:116342:44
From previous event:
    at Object.app.authenticate (http://localhost:3000/build/bundle.js:116331:26)
    at AuthStore.login (http://localhost:3000/build/bundle.js:51286:31)
    at helper (http://localhost:3000/build/bundle.js:143958:62)
    at helper (http://localhost:3000/build/bundle.js:143975:13)
    at helper (http://localhost:3000/build/bundle.js:143975:13)
    at access (http://localhost:3000/build/bundle.js:143941:11)
    at dispatch (http://localhost:3000/build/bundle.js:29245:40)
    at handleOnSubmitFormLogin (http://localhost:3000/build/bundle.js:49642:29)
    at Object.invokeGuardedCallback (http://localhost:3000/build/bundle.js:35690:13)
    at executeDispatch (http://localhost:3000/build/bundle.js:31089:22)
    at Object.executeDispatchesInOrder (http://localhost:3000/build/bundle.js:31112:6)
    at executeDispatchesAndRelease (http://localhost:3000/build/bundle.js:28554:23)
    at executeDispatchesAndReleaseTopLevel (http://localhost:3000/build/bundle.js:28565:11)
    at Array.forEach (native)
    at forEachAccumulated (http://localhost:3000/build/bundle.js:47496:10)
    at Object.EventPluginHub.processEventQueue (http://localhost:3000/build/bundle.js:28727:8)
    at runEventQueueInBatch (http://localhost:3000/build/bundle.js:140232:19)
    at Object.ReactEventEmitterMixin.handleTopLevel [as _handleTopLevel] (http://localhost:3000/build/bundle.js:140243:6)
    at handleTopLevelImpl (http://localhost:3000/build/bundle.js:140325:25)

Support objects as second parameter to #on and #off

When using DOM Events, you can pass either a function as the eventListener parameter or an object that implements the EventListener interface, ie. the single handleEvent method, to the addEventListener and removeEventListener methods.

This is a very valuable feature since you can have object prototype implement the handleEvent method and do event routing there while being able to pass an instance to addEventListener and removeEventListener.

Without this feature, it's tricky to remove event listeners within the scope of an instance since the alternative is to use Function.bind() to generate an event listener, and thus keep track of the generated function to be able to remove it later on.

I'd like to propose that component/emitter supports this as well and that the on and off methods allow objects to be passed implementing a similar interface to DOM's EventListener.

package name is incorrect in package.json

When I do the following

npm install component/upload and try to run I get the error cannot require emitter

then I run
npm install component/emitter and I still get the error. because in package.json the package name is component-emitter while in component.json it is emitter.

Listen to all/pipe

Could we have a way of listening to all events, such that you receive event name and arguments? What I want to do is implement a kind of pipe operation which would listen to all events emitted by A and then emit them on B and could be used like:

A.pipe(B);

Handle unhandled.

There should be reserved unhandled event called every time when event without callback is fired. To do so You should change your emit function to something like:

Emitter.prototype.emit = function(event){
    this._callbacks = this._callbacks || {};
    var args = [].slice.call(arguments, 1)
        , callbacks = this._callbacks[event] || this._callback['unhandled'];

    if (callbacks) {
        callbacks = callbacks.slice(0);
        for (var i = 0, len = callbacks.length; i < len; ++i) {
            callbacks[i].apply(this, args);
        }
    } 

    return this;
};

It would make life (and debugging), a lot, lot easier.

npm ERR! 403 Forbidden - archive/1.0.1.tar.gz

From: audreyt/ethercalc#548

Any ideas what is causing this error:

npm ERR! 403 Forbidden: emitter@http://github.com/component/emitter/archive/1.0.1.tar.gz

I see there is no folder /archive/

My emitter/package.json


{
  "_args": [
    [
      {
        "raw": "emitter@http://github.com/component/emitter/archive/1.0.1.tar.gz",
        "scope": null,
        "escapedName": "emitter",
        "name": "emitter",
        "rawSpec": "http://github.com/component/emitter/archive/1.0.1.tar.gz",
        "spec": "http://github.com/component/emitter/archive/1.0.1.tar.gz",
        "type": "remote"
      },

...

Avoid constructor call

  • Emitter#emit / Emitter#off / Emitter#has should check that this.callbacks is defined or return right away
  • Emitter#on should define the callbacks hash if absent
  • The constructor should be noop

Just some random questions

I am trying to learn more about this library but i had some questions.

well in all honesty, i am a little lost on how this works.

  1. If i take this example in the Readme
import Emitter from 'component-emitter';

const emitter = new Emitter();

emitter.emit('๐Ÿฆ„');

If i understand correctly, you can create a new Emitter and register listeners to it. When you do, you create it with an event type. then using emit, you pass in that event type. then some listners like Emitter#on will run what ever you pass in

is that correct so far?

  1. To follow up, may i ask for an explanation on this example
import Emitter from 'component-emitter';

Emitter(User.prototype);

what does this do ? does it mean it uses the passed in object as a way to detect for events? I found another library that used the prototype of an advance nodejs class into the component-emitter constructor, but i am not sure what changes that vs an empty create of a component-emitter instance.

thanks in advance!

Setting max listener count

Hi,
Is there a way to set a setMaxListeners for you Emitter object ? Standard Node Js EventEmitter provides the function setMaxListeners(). It's a very useful function. It allows me to detect memory leaks when the same listener is attached to the Emitter more than once.

Thank's for you great work. It's a very nice and useful library !

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.