arbitrary-emitter
Advanced tools
Comparing version 0.9.0 to 0.10.0
'use strict' | ||
function arbitrary () { | ||
const listeners = new Map() | ||
const events = new Map() | ||
const actions = new Map() | ||
function setEmitters (lis, triggers) { | ||
const size = triggers.size | ||
if (!size) listeners.delete(lis.key) | ||
else if (size === 1) { | ||
let fn | ||
triggers.forEach(f => { fn = f }) | ||
lis.launch0 = lis.launch1 = fn | ||
lis.launchX = args => fn.apply(fn, args) | ||
function setActions (e, listeners) { | ||
const size = listeners.length | ||
if (!size) { | ||
events.delete(e.key) | ||
actions.delete(e.key) | ||
} else if (size === 1) { | ||
actions.set(e.key, listeners[0]) | ||
} else { | ||
lis.launch0 = () => triggers.forEach(f => f()) | ||
lis.launch1 = (a, b) => triggers.forEach(f => f(a, b)) | ||
lis.launchX = lis.trigger | ||
actions.set(e.key, opts => { | ||
for (let i = 0; i < size; i++) { | ||
listeners[i](opts) | ||
} | ||
}) | ||
} | ||
@@ -22,31 +24,33 @@ } | ||
const newListener = key => { | ||
const triggers = new Set() | ||
const listeners = [] | ||
const lis = { | ||
const e = { | ||
key, | ||
add (fn) { | ||
triggers.add(fn) | ||
setEmitters(lis, triggers) | ||
if (listeners.indexOf(fn) === -1) { | ||
listeners.push(fn) | ||
} | ||
setActions(e, listeners) | ||
}, | ||
rm (method) { | ||
triggers.delete(method) | ||
setEmitters(lis, triggers) | ||
}, | ||
trigger (args) { | ||
triggers.forEach(f => f.apply(f, args)) | ||
rm (lis) { | ||
let index = listeners.indexOf(lis) | ||
if (index > -1) { | ||
listeners.splice(index, 1) | ||
setActions(e, listeners) | ||
} | ||
} | ||
} | ||
listeners.set(key, lis) | ||
return lis | ||
events.set(key, e) | ||
return e | ||
} | ||
return { | ||
on (key, method) { | ||
const lis = listeners.get(key) || newListener(key) | ||
lis.add(method) | ||
on (key, lis) { | ||
const e = events.get(key) || newListener(key) | ||
e.add(lis) | ||
let isSubscribed = true | ||
return () => { | ||
if (isSubscribed) { | ||
lis.rm(method) | ||
e.rm(lis) | ||
isSubscribed = false | ||
@@ -57,42 +61,23 @@ } | ||
once (key, method) { | ||
const lis = listeners.get(key) || newListener(key) | ||
lis.add(fn) | ||
once (key, lis) { | ||
const e = events.get(key) || newListener(key) | ||
e.add(fn) | ||
function fn () { | ||
method(arguments) | ||
lis.rm(fn) | ||
lis(arguments) | ||
e.rm(fn) | ||
} | ||
}, | ||
emit (key) { | ||
const lis = listeners.get(key) | ||
if (!lis) return | ||
const al = arguments.length | ||
if (al === 1) lis.launch0() | ||
else if (al > 4) lis.launch1(arguments[1], arguments[2]) | ||
else { | ||
let args = new Array(al - 1) | ||
for (let i = 1; i < al; ++i) { | ||
args[i - 1] = arguments[i] | ||
} | ||
lis.launchX(args) | ||
} | ||
emit (key, opts) { | ||
const action = actions.get(key) | ||
if (action) action(opts) | ||
}, | ||
trigger (key) { | ||
const lis = listeners.get(key) | ||
if (!lis) return | ||
if (arguments.length === 1) { | ||
return lis.launch0() | ||
off (key, lis) { | ||
if (!(1 in arguments)) { | ||
events.delete(key) | ||
actions.delete(key) | ||
} else if (events.has(key)) { | ||
events.get(key).rm(lis) | ||
} | ||
let args = arguments[1] | ||
if (typeof args !== 'object') { | ||
throw new Error('arguments has wrong type') | ||
} | ||
lis.trigger(args) | ||
}, | ||
off (key, action) { | ||
if (!(1 in arguments)) listeners.delete(key) | ||
else if (listeners.has(key)) listeners.get(key).rm(action) | ||
} | ||
@@ -99,0 +84,0 @@ } |
{ | ||
"name": "arbitrary-emitter", | ||
"version": "0.9.0", | ||
"description": "Event emitter with Map/Set sugar for modern browsers and node.js", | ||
"version": "0.10.0", | ||
"description": "Event emitter with ES6 Map sugar for modern browsers and node.js", | ||
"main": "arbitrary-emitter.js", | ||
@@ -33,5 +33,5 @@ "scripts": { | ||
"browserify": "^13.0.1", | ||
"standard": "^7.0.1", | ||
"standard": "^7.1.1", | ||
"tape": "^4.5.1" | ||
} | ||
} |
arbitrary-emitter | ||
================= | ||
Event emitter with Map/Set sugar for modern browsers and node.js (~500 bytes). [arbitrary-emitter.jacoborus.codes](http://arbitrary-emitter.jacoborus.codes) | ||
Event emitter with ES6 Map sugar for modern browsers and node.js (~400 bytes). [arbitrary-emitter.jacoborus.codes](http://arbitrary-emitter.jacoborus.codes) | ||
@@ -16,3 +16,3 @@ [![Build Status](https://travis-ci.org/jacoborus/arbitrary-emitter.svg?branch=master)](https://travis-ci.org/jacoborus/arbitrary-emitter) [![npm version](https://badge.fury.io/js/arbitrary-emitter.svg)](https://www.npmjs.com/package/arbitrary-emitter) | ||
- allows to use **arbitrary values** as keys for listeners | ||
- really small footprint (**~500 bytes** when gzipped) | ||
- really small footprint (**~400 bytes** when gzipped) | ||
- **blazing fast** | ||
@@ -28,6 +28,6 @@ - conventional api (`on`, `off`, `once` and `emit`) | ||
const emitter = arbitraryEmitter() | ||
const obj = {} | ||
emitter.on(obj, () => doSomething()) | ||
const key = {} | ||
emitter.on(key, () => doSomething()) | ||
// will `doSomething` | ||
emitter.emit(obj) | ||
emitter.emit(key) | ||
``` | ||
@@ -38,16 +38,15 @@ | ||
<a name="emitter-on-api"></a> | ||
### on(key, action) | ||
### on(eventKey, listener) | ||
Adds the listener `action` to the `Set` for the event tagged with `key`. | ||
`key` can be any type of value. | ||
Adds the `listener` function to the end of the listeners array for the event tagged with `eventKey`. `eventKey` can be any type of value. A check is made to see if the listener has already been added so it won't be called multiple times. Event listeners are invoked in the order they are added. | ||
`on` returns removeListener method | ||
`on` returns removeListener method | ||
```js | ||
const obj = {} | ||
let removeListener = emitter.on(obj, () => doSomething()) | ||
emitter.emit(obj) // will `doSomething` | ||
emitter.emit(obj) // will `doSomething` | ||
const key = {} | ||
let removeListener = emitter.on(key, () => doSomething()) | ||
emitter.emit(key) // will `doSomething` | ||
emitter.emit(key) // will `doSomething` | ||
removeListener() | ||
emitter.emit(obj) // won't do anything | ||
emitter.emit(key) // won't do anything | ||
``` | ||
@@ -58,12 +57,11 @@ | ||
<a name="emitter-addonce-api"></a> | ||
### once(key, action) | ||
### once(eventKey, listener) | ||
Adds the listener `action` to the `Set` for the event tagged with `key`. `action` will be triggered just one time, then it will be removed. | ||
`key` can be any type of value | ||
Same as `on`, but `listener` will be triggered just one time, then it will be removed. | ||
```js | ||
const obj = {} | ||
emitter.once(obj, () => doSomethingOnce()) | ||
emitter.emit(obj) // will `doSomethingOnce` | ||
emitter.emit(obj) // won't do anything | ||
const key = {} | ||
emitter.once(key, () => doSomethingOnce()) | ||
emitter.emit(key) // will `doSomethingOnce` | ||
emitter.emit(key) // won't do anything | ||
``` | ||
@@ -74,9 +72,10 @@ | ||
<a name="emitter-emit-api"></a> | ||
### emit(key[, ...args]) | ||
### emit(eventKey[, options]) | ||
Synchronously calls each of the listeners registered for the event tagged with `key`, and pass the rest of the arguments to them | ||
Synchronously calls each of the listeners registered for the event tagged with `eventKey`, passing the supplied argument `options` to each | ||
```js | ||
emitter.on('test', (a, b) => console.log(a + b)) | ||
emitter.emit('test', 1, 2) // => 3 | ||
emitter.on('test', (opts) => console.log(opts.test)) | ||
const options = { test: 'Testing!' } | ||
emitter.emit('test', options) // => 'Testing!' | ||
``` | ||
@@ -86,18 +85,8 @@ | ||
<a name="emitter-trigger-api"></a> | ||
### trigger(key[, args]) | ||
Synchronously calls each of the listeners registered for the event tagged with `key`, and pass `args` array as arguments to them | ||
```js | ||
emitter.on('test', (a, b) => console.log(a + b)) | ||
emitter.trigger('test', [1, 2]) // => 3 | ||
``` | ||
<a name="emitter-off-api"></a> | ||
### off(key[, action]) | ||
### off([eventKey[, listener]]) | ||
Remove `action` from listeners tagged with `key`. If no `action` is specified will remove all listeners tagged with `key` | ||
- When no argument is passed all the listeners and its eventKeys will be removed from the emitter | ||
- If an `eventKey` but no `listener` is passed all the listeners and its key will be removed | ||
- If `eventKey` and `listener` are passed as arguments just the listener will be removed from its group | ||
@@ -107,2 +96,3 @@ ```js | ||
emitter.off(key) // will remove all the listeners tagged with `key`, and the tag itself | ||
emitter.off() // will remove all the listeners from all the eventKeys and the eventKeys themselves | ||
``` | ||
@@ -109,0 +99,0 @@ |
@@ -10,3 +10,4 @@ 'use strict' | ||
let control = 0 | ||
let unsubscribe = emitter.on(obj, () => ++control) | ||
const fn = () => ++control | ||
let unsubscribe = emitter.on(obj, fn) | ||
emitter.emit(obj) | ||
@@ -16,5 +17,8 @@ t.is(control, 1, 'trigger') | ||
t.is(control, 2, 'trigger') | ||
emitter.on(obj, fn) | ||
emitter.emit(obj) | ||
t.is(control, 3, 'trigger') | ||
unsubscribe() | ||
emitter.emit(obj) | ||
t.is(control, 2, 'unsubscribe') | ||
t.is(control, 3, 'unsubscribe') | ||
t.end() | ||
@@ -94,67 +98,10 @@ }) | ||
let control = { | ||
a: 0, | ||
b: 0, | ||
c: 0 | ||
a: 0 | ||
} | ||
emitter.on(obj, (a, b, c) => { | ||
control.a = a | ||
control.b = b | ||
control.c = c | ||
}) | ||
emitter.on(obj, a => { control.a = a }) | ||
emitter.emit(obj, 1, 2, 3) | ||
emitter.emit(obj, 1) | ||
t.is(control.a, 1) | ||
t.is(control.b, 2) | ||
t.is(control.c, 3) | ||
t.end() | ||
}) | ||
test('trigger actions in order', t => { | ||
const emitter = ae() | ||
const obj = {} | ||
let control = '' | ||
emitter.on(obj, () => { control = control + 'a' }) | ||
emitter.trigger(obj) | ||
t.is(control, 'a', 'trigger') | ||
emitter.trigger(obj) | ||
t.is(control, 'aa', 'trigger') | ||
emitter.on(obj, () => { control = control + 'b' }) | ||
emitter.trigger(obj) | ||
t.is(control, 'aaab', 'unsubscribe') | ||
emitter.on(obj, () => { control = control + 'c' }) | ||
emitter.trigger(obj) | ||
t.is(control, 'aaababc', 'unsubscribe') | ||
t.end() | ||
}) | ||
test('trigger with arguments', t => { | ||
const emitter = ae() | ||
const obj = {} | ||
let control = { | ||
a: 0, | ||
b: 0, | ||
c: 0 | ||
} | ||
emitter.on(obj, (a, b, c) => { | ||
control.a = a | ||
control.b = b | ||
control.c = c | ||
}) | ||
emitter.trigger(obj, [1, 2, 3]) | ||
t.is(control.a, 1) | ||
t.is(control.b, 2) | ||
t.is(control.c, 3) | ||
t.throws( | ||
() => emitter.trigger(obj, 1), | ||
/arguments has wrong type/, | ||
'throws on wrong arguments list type' | ||
) | ||
t.end() | ||
}) |
10675
167
123