Norwegian Parcel Mail

    kilo-emitter
    TypeScript icon, indicating that this package has built-in type declarations

    0.1.8 • Public • Published

    What & Why

    A sub 1Kb event emitter class with broader functionality.

    Why another one ?

    I needed some specific but not unheard of features of event emitter and all the lightweight implementations I founds were all missing one or the other, so I ended up making my own with set of features that I needed. It's not better or worse than other ones, it just combines a specific set.

    So here's what I needed from event emitter and ended up implementing in this one:

    • Small footprint, 1Kb or less.
    • Chainalbe methods.
    • Instantiate with new as well as extend existing object.
    • Reliable listener removal (usually once were implemented as wrappers so you couldn't remove them by same listener reference).
    • Ability to remove all listeners for given event. See .off(event)
    • Ability to remove all listeners for all events. See .off(event)
    • Priority listeners (added to the start of the queue instead of end). See .on()
    • Ability to pass context to the listener as this keyword. See .on()
    • Ability to stop propagation of current event, smth like preventDefaults. See .emit()
    • Ability to pass arguments together with event. See .emit()
    • Ability to check whether specific listener is subscribed for a specific event. See .triggers()
    • Ability to check whether emitter has any listeners subscribed for specified event or any listeners at all. See .triggers()
    • Available under diferent formats (ES3, ES5, ES6, Browser, inlined)

    Stats

    Coverage

    Type Coverage
    Statements 100% (130/130)
    Branches 100% (84/84)
    Functions 100% (18/18)
    Lines 100% (126/126)

    dist directory size listing

    Name Bytes Gzip %
    Emitter.es3.browser.js 3289 813 24%
    Emitter.es3.browser.min.js 1022 501 49%
    Emitter.es3.inlined.js 3286 810 24%
    Emitter.es3.inlined.min.js 1019 499 48%
    Emitter.es3.umd.js 4120 976 23%
    Emitter.es3.umd.min.js 1276 607 47%
    Emitter.es6.inlined.js 3069 789 25%
    Emitter.es6.inlined.min.js 883 481 54%
    Emitter.es6.js 3076 794 25%
    Emitter.es6.min.js 899 493 54%
    Emitter.js 3161 843 26%
    Emitter.min.js 975 535 54%

    Usage

    Package manager
    npm i kilo-emitter
    yarn add kilo-emitter
    Browser tag
    <script src="https://unpkg.com/kilo-emitter/dist/Emitter.es3.browser.min.js"></script>
    Inlined

    Or you can just grab this compiled inlined version and copy-paste it in your code.

    ES3, 1019 Bytes

    var Emitter=function(){function t(){this.$evt={}}return t.extend=function(e){var n;return e&&"object"==typeof e&&(n=new t,["$evt","on","off","once","emit","triggers"].forEach(function(t){e[t]=n[t]})),e},t.prototype.on=function(t,e,n,o){var i,r=this.$evt;return t&&e&&("boolean"==typeof n?(o=n,n=null):e.$ctx=n,(i=r[t])?(this.off(t,e),o?i.unshift(e):i.push(e)):i=[e],r[t]=i),this},t.prototype.once=function(t,e,n,o){return t&&e&&(e.$once=!0,this.on(t,e,n,o)),this},t.prototype.off=function(t,e){var n,o,i=arguments.length,r=this.$evt;return 0===i?this.$evt={}:1===i?delete r[t]:-1<(n=(o=r[t])?o.indexOf(e):-1)&&(o.splice(n,1),o.length||delete r[t]),this},t.prototype.emit=function(t,e){var n,o,i,r=this.$evt[t];if(r&&(i=r.length))for(r=r.slice(),n=0;n<i;n++)"stopEmit"===(o=r[n]).apply(o.$ctx,e)&&(n=i),o.$once&&(this.off(t,o),delete o.$once);return this},t.prototype.triggers=function(t,e){var n,o=arguments.length,i=this.$evt;return o?!!(n=i[t])&&(!(1<o)||-1<n.indexOf(e)):!!Object.getOwnPropertyNames(i).length},t}();

    ES6, 883 Bytes

    class Emitter{static extend(t){let e;return t&&"object"==typeof t&&(e=new Emitter,["$evt","on","off","once","emit","triggers"].forEach(n=>{t[n]=e[n]})),t}constructor(){this.$evt={}}on(t,e,n,i){let s,r=this.$evt;return t&&e&&("boolean"==typeof n?(i=n,n=null):e.$ctx=n,(s=r[t])?(this.off(t,e),i?s.unshift(e):s.push(e)):s=[e],r[t]=s),this}once(t,e,n,i){return t&&e&&(e.$once=!0,this.on(t,e,n,i)),this}off(t,e){let n,i,s=arguments.length,r=this.$evt;return 0===s?this.$evt={}:1===s?delete r[t]:(n=(i=r[t])?i.indexOf(e):-1)>-1&&(i.splice(n,1),i.length||delete r[t]),this}emit(t,e){let n,i,s,r=this.$evt[t];if(r&&(s=r.length))for(r=r.slice(),n=0;n<s;n++)"stopEmit"===(i=r[n]).apply(i.$ctx,e)&&(n=s),i.$once&&(this.off(t,i),delete i.$once);return this}triggers(t,e){let n,i=arguments.length,s=this.$evt;return i?!!(n=s[t])&&(!(i>1)||n.indexOf(e)>-1):!!Object.getOwnPropertyNames(s).length}}
    Node
    const Emitter = require('kilo-emitter')
    let cb = (World) => { console.log(`Hello ${World}!`) }
     
    let myEmitter = new Emitter()
    myEmitter.on('evt', cb)
    myEmitter.emit('evt', ['World']) // `Hello World!`
    console.log(myEmitter.triggers('evt', cb)) // true
    myEmitter.off('evt')
    console.log(myEmitter.triggers('evt', cb)) // false
    ES6/TypeScript
    import Emitter from 'kilo-emitter'
     
    let myEmitter = new Emitter()
    myEmitter.once('evt', console.log)
    myEmitter.once('evt2', console.log)
    myEmitter.emit('evt', ['hey there']) // 'hey there'
    console.log(myEmitter.triggers('evt', console.log)) // false
    console.log(myEmitter.triggers()) // true
    myEmitter.off()
    console.log(myEmitter.triggers()) // false
    Browser
    <script src="https://unpkg.com/kilo-emitter/dist/Emitter.es3.browser.min.js"></script>
     
    <script>
    var myEmitter = new Emitter()
    myEmitter.once('evt', (param) => {
         console.log(`Hey ${param}!`)
        }, ['there'])
    myEmitter.emit('evt')
    </script> 

    API

    static extend(target)

    Extends target object that is passed to it with Emitter class methods. It creates new Emitter class and assigns all of it's fields and methods (including $evt) to target object. Note that those methods will override existing fields with same names and also should now be invoked on target since they rely on this keyword.

    function extend<T extends object>(target: T): T & Emitter
    • target object An object that will be extended.
    let someObject = {someField: 'someValue'}
    Emitter.extend(someObject)
     
    someObject.on('evt', function (someParam) {
      console.log(someParam) // 'otherValue'
      console.log(this.someField) // 'someValue'
    })
    someObject.emit('evt', ['otherValue'])

    on(event, listener, context, priority)

    Subscribes a listener to an event. Listener will persist until removed with .off(). Subscribing an existing listener again will move it to the end (or start, if priority specified) of the queue. Unique listener is considered a combo of an event name and a reference to a function. If a same callback added with a different context it will be considered as a same listener. Context parameter is skipable, if you pass boolean as 3rd argument it will be used as priority.

    function on(event: string, listener: Listener, context?: object|boolean, priority?:Boolean) : this
    • event string Event name you want to subscribe to.
    • listener Listener Listener callback to be invoked.
    • context object|boolean optional Context to invoke callback with (pass as this) OR a boolean value for priority if you want to skip context
    • priority Boolean optional If true will add listener to the start of the queue.
    let em = new Emitter()
     
    em.on('evt', (val) => {}) // regular listener
    em.on('evt', (val) => {}, {someField: 'someValue'}) // listener with context
    em.on('evt', (val) => {}, null, true) // listener with priority (added to the start of queue)
    em.on('evt', (val) => {}, true) // same
     
    em.emit('evt', ['otherValue'])

    once(event, listener, context, priority)

    Same as .on() but listener will be automatically removed after first invocation.

    function once(event: string, listener: Listener, context?: object, priority?:Boolean) : this
    • event string Event name you want to subscribe to.
    • listener Listener Listener callback to be invoked.
    • context object|boolean optional Context to invoke callback with (pass as this) OR a boolean value for priority if you want to skip context
    • priority Boolean optional If true will add listener to the start of the queue.
    let em = new Emitter()
    let cb = () => {}
     
    em.once('evt', cb)
    console.log( em.triggers('evt', cb) ) // true
     
    em.emit('evt')
    console.log( em.triggers('evt', cb) ) // false

    off(event, listener)

    If both arguments are passed it removes the listener if such exists. If only event name is passed it will remove all the listeners for that event. If no arguments passed it will purge all the listeners for current emitter. Distinction is made by the length of the arguments variable to avoid undesired behaviour when null or undefined are passed due to an error. This means that off('init') will try to remove all listeners for 'init' event and off(null) will try to remove all events for 'null' event.

    function off(event?: string, listener?: Function) : this
    • event string optional Event name you want to unsubscribe from.
    • listener Listener optional Listener callback you want to remove.
    let em = new Emitter()
    let cb = () => {}
    em.on('evt', cb) // removed on 1sk off
    em.on('evt', () => {}) // removed on 2sk off
    em.on('evt2', () => {}) // removed on 3sk off
    // removes specific listener
    em.off('evt', cb)
    // removes all listeners for event
    em.off('evt')
    // removes all listeners completely
    em.off()

    emit(event, args)

    If both arguments are passed it removes the listener if such exists. If only event name is passed it will remove all the listeners for that event. If no arguments passed it will purge all the listeners for current emitter. Distinction is made by the length of the arguments variable to avoid undesired behaviour when null or undefined are passed due to an error. This means that off('init') will try to remove all listeners for 'init' event and off(null) will try to remove all events for 'null' event.

    function emit(event: string, args?:any[]) : this
    • event string Event name whose listeners should be invoked.
    • args any[] optional Array of arguments that should be passed to each listener callback.
    let em = new Emitter()
     
    // this listeners stops propagation and removes itself
    em.once('evt', (arg1, arg2) => {
      console.log(arg1) // 'a'
      console.log(arg2) // 'b'
      return 'stopEmit'
    })
     
    // this listener is triggered on second emit
    em.on('evt', () => {
      // never triggered
    })
     
    em.emit('evt', ['a', 'b'])
    em.emit('evt')

    triggers(event, listener)

    If both arguments are passed then it will check whether specific listener is subscribed for specific event. If only event name is passed it will check if there are any listeners subscribed for that event. If no arguments passed it will check if emitter has any listeners at all. Distinction is made by the length of the arguments variable to avoid undesired behaviour when null or undefined are passed due to an error. This means that triggers('init') will check if there are any listeners fot the event 'init' and triggers(null) will check if there are any listeners fot the event 'null'.

    function triggers(event?: string, listener?: Function): boolean
    • event string optional Event name for which to look.
    • listener Function optional Reference to a function instance that was used when subscribing.
    let em = new Emitter()
    let cb = () => {}
     
    em.on('evt', cb)
    em.on('evt', () => {})
    em.on('evt3', () => {})
     
    console.log( em.triggers('evt', cb) ) // true
    em.off('evt', cb)
    console.log( em.triggers('evt', cb) ) // false
     
    console.log( em.triggers('evt') ) // true
    em.off('evt')
    console.log( em.triggers('evt') ) // false
     
    console.log( em.triggers() ) // true
    em.off()
    console.log( em.triggers() ) // false

    Install

    npm i kilo-emitter

    DownloadsWeekly Downloads

    18

    Version

    0.1.8

    License

    MIT

    Unpacked Size

    82.7 kB

    Total Files

    21

    Last publish

    Collaborators

    • n1kk