New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

async-cancelable-events

Package Overview
Dependencies
Maintainers
1
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

async-cancelable-events - npm Package Compare versions

Comparing version 0.0.1 to 0.0.2

99

lib/async-cancelable-events.js
var isAsync = require('is-async');
// ## printMaxListenersWarning
// is a listener that prints a warning when the max listeners has been exceeded just
// like the ``EventEmitter`` does, but now you can clear it out by executing
// ``this.removeAllListeners('maxListenersPassed')`` in your constructor function
// just after running the ``AsyncCancelableEvents`` constructor function in your own
// constructor function.
function printMaxListenersWarning(eventName, listenerCount) {
console.warn('The Event ' + eventName + ' has exceeded ' + this._maxListeners + ' listeners, currently at ' + listenerCount);
}
// # AsyncCancelableEvents
// constructor function, a drop-in replacement for ``EventEmitter`` almost every time
// (excepting when an event emits a function, then use ``emitSync``) that also allows
// the event listeners to cancel events if ``emit`` is provided with a callback.
// Event listeners may be either synchronous like DOM events or asynchronous to better
// fit the Node.js style. (Because of that, making an event placed inside of a high
// performance loop is probably a bad idea because the event listeners can introduce
// an unpredictable delay.) The ``AsyncCancelableEvents`` constructor function attaches
// three "please don't touch" properties to itself (or its inheriting object) to keep
// track of listeners and the maximum number of allowed listeners.
function AsyncCancelableEvents() {

@@ -7,8 +27,23 @@ this._eventListeners = {};

this._maxListeners = 10;
this.on('maxListenersPassed', printMaxListenersWarning.bind(this));
}
// ## emit
// takes and event name and a variable number of arguments. If the last argument is a
// function, it assumes it's a callback for the event and that this event is cancelable.
// Listeners can only cancel events if their return value (or callback parameter) is
// ``false``, any other value is considered ``true`` and the event continues. Event
// cancelation immediately ends all processing of event listeners. The order of event
// listeners is roughly that of the order they were attached, but ``once`` listeners
// are given priority over ``on`` listeners (so its possible to do a one-time
// cancelation and not have any of the ``on`` listeners called).
AsyncCancelableEvents.prototype.emit = function emit(eventName) {
// Get the list of arguments for the listeners into an array
var argsArray = Array.prototype.slice.call(arguments, 1, arguments.length);
// If the last argument is a function, assume its a callback for ``emit`` and pop it off
var callback = argsArray[argsArray.length-1] instanceof Function ? argsArray[argsArray.length-1] : undefined;
if(callback) argsArray.pop();
// Create an array of listeners to call for this particular event, taking the ``once``
// listeners first and firing the removeListener event, then attaching any ``on``
// listeners. In both cases only if they exist.
var listenersToCall = [];

@@ -23,2 +58,8 @@ if(this._oneTimeListeners[eventName] instanceof Array) {

if(this._eventListeners[eventName] instanceof Array) Array.prototype.push.apply(listenersToCall, this._eventListeners[eventName]);
// An asynchronous iterator for the listeners. If the return value given to it is ``false``,
// immediately end and call the callback, if it exists, otherwise if there are still listeners
// to call, call them (determining whether or not the listener is asynchronous) and pass the
// result into the iterator function (either by callback or simply calling itself recursively
// if synchronous). If there are no more listeners to call and none of them returned ``false``,
// finally return ``true`` to the callback function, if it exists.
var iterate = function iterate(retVal) {

@@ -44,8 +85,19 @@ if(retVal === false) {

argsArray.push(iterate);
// Call the iterate function with ``true`` to kick off the recursive process
iterate(true);
// Whenever possible, have the methods return ``this`` so they can be chained
return this;
};
// ## emitAsync
// In this case, forcing async means the same thing as the normal version of the function
AsyncCancelableEvents.prototype.emitAsync = AsyncCancelableEvents.prototype.emit;
// ## emitSync
// Unfortunately for synchronous emit, the logic is changed enough that simply wrapping
// ``sync`` (as done below with other methods) is not possible, but the overall pattern
// of getting the arguments, the listeners to call, and iterating through them is still
// the same. In this case, however, the last argument is always passed to the listeners
// and what the listeners return is only checked for canceling the listeners calling list,
// the result is never returned.
AsyncCancelableEvents.prototype.emitSync = function emitSync(eventName) {

@@ -82,2 +134,11 @@ var argsArray = Array.prototype.slice.call(arguments, 1, arguments.length);

// ## on
// The bread-n-butter of an EventEmitter, registering listeners for events. In this
// implementation, the event types are lazily determined, as this is the most
// obvious implementation for Javascript, and high performance for registering
// listeners shouldn't be an issue. If the total number of listeners exceeds the
// maximum specified, the ``maxListenersPassed`` event is fired with the event name
// and listener count as arguments provided to the listener. Like all events internal
// to ``AsyncCancelableEvents``, it is not cancelable, itself. Once registered, the
// ``newListener`` event is emitted.
AsyncCancelableEvents.prototype.on = function on(eventName, listener) {

@@ -93,2 +154,6 @@ if(!this._eventListeners) this._eventListeners = {};

// ## onSync
// Taking advantage of the ``is-async`` method's behavior, registering a forced
// synchronous event simply requires attaching a truthy ``sync`` property to the
// method and then registering it as usual.
AsyncCancelableEvents.prototype.onSync = function onSync(eventName, listener) {

@@ -99,2 +164,4 @@ listener.sync = true;

// ## onAsync
// Similarly for forced asynchronous functions, just attach a truthy ``async`` property
AsyncCancelableEvents.prototype.onAsync = function onAsync(eventName, listener) {

@@ -105,2 +172,6 @@ listener.async = true;

// ## addListener, addListenerSync, addListenerAsync
// These methods are just synonyms for the ``on*`` methods, kept just to make sure
// ``AsyncCancelableEvents`` should "just work" for the majority of use-cases of
// ``EventEmitter``.
AsyncCancelableEvents.prototype.addListener = AsyncCancelableEvents.prototype.on;

@@ -110,2 +181,6 @@ AsyncCancelableEvents.prototype.addListenerSync = AsyncCancelableEvents.prototype.onSync;

// ## once
// The ``once`` method works very similar to the ``on`` method, except it operates on the
// ``_oneTimeListeners`` property, instead. This could probably be DRYed out a bit, but
// will only save a few lines of code and I don't expect this library to change much.
AsyncCancelableEvents.prototype.once = function once(eventName, listener) {

@@ -121,2 +196,5 @@ if(!this._oneTimeListeners) this._oneTimeListeners = {};

// ## onceSync
// Exactly like ``onSync``, but with a different method involved. Attempting to DRY
// this would produce a net *gain* in lines of code.
AsyncCancelableEvents.prototype.onceSync = function onceSync(eventName, listener) {

@@ -127,2 +205,4 @@ listener.sync = true;

// ## onceAsync
// Exactly like ``onAsync`` but for ``once``.
AsyncCancelableEvents.prototype.onceAsync = function onceAsync(eventName, listener) {

@@ -133,2 +213,6 @@ listener.async = true;

// ## removeListener
// Checks if the event has any listeners registered and then filters out the provided listener,
// firing the ``removeListener`` event if found. It must be a reference to the same function,
// not just have equal ``toString`` results.
AsyncCancelableEvents.prototype.removeListener = function removeListener(eventName, listener) {

@@ -154,2 +238,6 @@ if(this._eventListeners[eventName] instanceof Array) this._eventListeners[eventName] = this._eventListeners[eventName].filter(function(registeredListener) {

// ## removeAllListeners
// If an event name is provided, it removes all of the listeners for that event (if the event
// exists) and emits the ``removeListener`` event for each listener. If not called with an
// event name, it generates a list of events and recursively calls itself for each event.
AsyncCancelableEvents.prototype.removeAllListeners = function removeAllListeners(eventName) {

@@ -180,2 +268,4 @@ if(eventName) {

// ## setMaxListeners
// 'Nuff said.
AsyncCancelableEvents.prototype.setMaxListeners = function setMaxListeners(count) {

@@ -186,2 +276,6 @@ this._maxListeners = count;

// ## listeners
// Returns an array of registered listeners for the given event. This array is a copy
// so you can alter it at will, but the functions it points to are not copies, so
// properties attached to them will propagate back into ``AsyncCancelableEvents``.
AsyncCancelableEvents.prototype.listeners = function listeners(eventName) {

@@ -194,2 +288,6 @@ var registeredListeners = [];

// ## listenerCount
// Not sure why ``EventEmitter`` didn't make this a prototype method, but here you go.
// Given an ``AsyncCancelableEvents`` instance and an event name, it returns the number
// of listeners registered on that event.
AsyncCancelableEvents.listenerCount = function listenerCount(instance, eventName) {

@@ -202,2 +300,3 @@ var count = 0;

// Export ``AsyncCancelableEvents``
module.exports = AsyncCancelableEvents;

2

lib/async-cancelable-events.min.js

@@ -1,1 +0,1 @@

(function(e,t,n){function r(n,s){if(!t[n]){if(!e[n]){var o=typeof require=="function"&&require;if(!s&&o)return o(n,!0);if(i)return i(n,!0);throw new Error("Cannot find module '"+n+"'")}var u=t[n]={exports:{}};e[n][0](function(t){var i=e[n][1][t];return r(i?i:t)},u,u.exports)}return t[n].exports}var i=typeof require=="function"&&require;for(var s=0;s<n.length;s++)r(n[s]);return r})({1:[function(e,t,n){function i(){this._eventListeners={},this._oneTimeListeners={},this._maxListeners=10}var r=e("is-async");i.prototype.emit=function(t){var n=Array.prototype.slice.call(arguments,1,arguments.length),i=n[n.length-1]instanceof Function?n[n.length-1]:undefined;i&&n.pop();var s=[];this._oneTimeListeners[t]instanceof Array&&(s=this._oneTimeListeners[t],delete this._oneTimeListeners[t],s.forEach(function(e){this.emitSync("removeListener",e)}.bind(this))),this._eventListeners[t]instanceof Array&&Array.prototype.push.apply(s,this._eventListeners[t]);var o=function u(e){if(e===!1)i&&i(!1);else if(s.length){var t=s.shift();if(r(t,n.length))t.apply(null,n);else{n.pop();var o=t.apply(null,n);n.push(u),u(o)}}else i&&i(!0)};return n.push(o),o(!0),this},i.prototype.emitAsync=i.prototype.emit,i.prototype.emitSync=function(t){var n=Array.prototype.slice.call(arguments,1,arguments.length),i=[];this._oneTimeListeners[t]instanceof Array&&(i=this._oneTimeListeners[t],delete this._oneTimeListeners[t],i.forEach(function(e){this.emitSync("removeListener",e)}.bind(this))),this._eventListeners[t]instanceof Array&&Array.prototype.push.apply(i,this._eventListeners[t]);var s=function o(e){if(e!==!1&&i.length){var t=i.shift();if(r(t,n.length))t.apply(null,n);else{n.pop();var s=t.apply(null,n);n.push(o),o(s)}}};return n.push(s),s(!0),this},i.prototype.on=function(t,n){this._eventListeners||(this._eventListeners={}),this._eventListeners[t]=this._eventListeners[t]instanceof Array?this._eventListeners[t]:[],this._eventListeners[t].push(n);var r=this._eventListeners[t].length+(this._oneTimeListeners[t]instanceof Array?this._oneTimeListeners[t].length:0);return r>this._maxListeners&&this.emitSync("maxListenersPassed",t,r),this.emitSync("newListener",n),this},i.prototype.onSync=function(t,n){return n.sync=!0,this.on(t,n)},i.prototype.onAsync=function(t,n){return n.async=!0,this.on(t,n)},i.prototype.addListener=i.prototype.on,i.prototype.addListenerSync=i.prototype.onSync,i.prototype.addListenerAsync=i.prototype.onAsync,i.prototype.once=function(t,n){this._oneTimeListeners||(this._oneTimeListeners={}),this._oneTimeListeners[t]=this._oneTimeListeners[t]instanceof Array?this._oneTimeListeners[t]:[],this._oneTimeListeners[t].push(n);var r=this._oneTimeListeners[t].length+(this._eventListeners[t]instanceof Array?this._eventListeners[t].length:0);return r>this._maxListeners&&this.emitSync("maxListenersPassed",t,r),this.emitSync("newListener",n),this},i.prototype.onceSync=function(t,n){return n.sync=!0,this.once(t,n)},i.prototype.onceAsync=function(t,n){return n.async=!0,this.once(t,n)},i.prototype.removeListener=function(t,n){return this._eventListeners[t]instanceof Array&&(this._eventListeners[t]=this._eventListeners[t].filter(function(e){return e===n?(this.emitSync("removeListener",n),!1):!0}.bind(this))),this._oneTimeListeners[t]instanceof Array&&(this._oneTimeListeners[t]=this._oneTimeListeners[t].filter(function(e){return e===n?(this.emitSync("removeListener",n),!1):!0}.bind(this))),this},i.prototype.removeAllListeners=function(t){return t?(this._eventListeners[t]instanceof Array&&(this._eventListeners[t].forEach(function(e){this.emitSync("removeListener",e)}.bind(this)),delete this._eventListeners[t]),this._oneTimeListeners[t]instanceof Array&&(this._oneTimeListeners[t].forEach(function(e){this.emitSync("removeListener",e)}.bind(this)),delete this._oneTimeListeners[t])):(Object.keys(this._eventListeners).forEach(function(e){this.removeAllListeners(e)}.bind(this)),Object.keys(this._oneTimeListeners).forEach(function(e){this.removeAllListeners(e)}.bind(this))),this},i.prototype.setMaxListeners=function(t){return this._maxListeners=t,this},i.prototype.listeners=function(t){var n=[];return this._eventListeners[t]instanceof Array&&Array.prototype.push.apply(n,this._eventListeners[t]),this._oneTimeListeners[t]instanceof Array&&Array.prototype.push.apply(n,this._oneTimeListeners[t]),n},i.listenerCount=function(t,n){var r=0;return t._eventListeners[n]instanceof Array&&(r+=t._eventListeners[n].length),t._oneTimeListeners[n]instanceof Array&&(r+=t._oneTimeListeners[n].length),r},t.exports=i},{"is-async":2}],2:[function(e,t,n){function r(e,t){return e.async||!e.sync&&e.length===t}t.exports=r},{}]},{},[1]);
(function(e,t,n){function r(n,s){if(!t[n]){if(!e[n]){var o=typeof require=="function"&&require;if(!s&&o)return o(n,!0);if(i)return i(n,!0);throw new Error("Cannot find module '"+n+"'")}var u=t[n]={exports:{}};e[n][0](function(t){var i=e[n][1][t];return r(i?i:t)},u,u.exports)}return t[n].exports}var i=typeof require=="function"&&require;for(var s=0;s<n.length;s++)r(n[s]);return r})({1:[function(e,t,n){(function(){function r(e,t){console.warn("The Event "+e+" has exceeded "+this._maxListeners+" listeners, currently at "+t)}function i(){this._eventListeners={},this._oneTimeListeners={},this._maxListeners=10,this.on("maxListenersPassed",r.bind(this))}var n=e("is-async");i.prototype.emit=function(t){var r=Array.prototype.slice.call(arguments,1,arguments.length),i=r[r.length-1]instanceof Function?r[r.length-1]:undefined;i&&r.pop();var s=[];this._oneTimeListeners[t]instanceof Array&&(s=this._oneTimeListeners[t],delete this._oneTimeListeners[t],s.forEach(function(e){this.emitSync("removeListener",e)}.bind(this))),this._eventListeners[t]instanceof Array&&Array.prototype.push.apply(s,this._eventListeners[t]);var o=function u(e){if(e===!1)i&&i(!1);else if(s.length){var t=s.shift();if(n(t,r.length))t.apply(null,r);else{r.pop();var o=t.apply(null,r);r.push(u),u(o)}}else i&&i(!0)};return r.push(o),o(!0),this},i.prototype.emitAsync=i.prototype.emit,i.prototype.emitSync=function(t){var r=Array.prototype.slice.call(arguments,1,arguments.length),i=[];this._oneTimeListeners[t]instanceof Array&&(i=this._oneTimeListeners[t],delete this._oneTimeListeners[t],i.forEach(function(e){this.emitSync("removeListener",e)}.bind(this))),this._eventListeners[t]instanceof Array&&Array.prototype.push.apply(i,this._eventListeners[t]);var s=function o(e){if(e!==!1&&i.length){var t=i.shift();if(n(t,r.length))t.apply(null,r);else{r.pop();var s=t.apply(null,r);r.push(o),o(s)}}};return r.push(s),s(!0),this},i.prototype.on=function(t,n){this._eventListeners||(this._eventListeners={}),this._eventListeners[t]=this._eventListeners[t]instanceof Array?this._eventListeners[t]:[],this._eventListeners[t].push(n);var r=this._eventListeners[t].length+(this._oneTimeListeners[t]instanceof Array?this._oneTimeListeners[t].length:0);return r>this._maxListeners&&this.emitSync("maxListenersPassed",t,r),this.emitSync("newListener",n),this},i.prototype.onSync=function(t,n){return n.sync=!0,this.on(t,n)},i.prototype.onAsync=function(t,n){return n.async=!0,this.on(t,n)},i.prototype.addListener=i.prototype.on,i.prototype.addListenerSync=i.prototype.onSync,i.prototype.addListenerAsync=i.prototype.onAsync,i.prototype.once=function(t,n){this._oneTimeListeners||(this._oneTimeListeners={}),this._oneTimeListeners[t]=this._oneTimeListeners[t]instanceof Array?this._oneTimeListeners[t]:[],this._oneTimeListeners[t].push(n);var r=this._oneTimeListeners[t].length+(this._eventListeners[t]instanceof Array?this._eventListeners[t].length:0);return r>this._maxListeners&&this.emitSync("maxListenersPassed",t,r),this.emitSync("newListener",n),this},i.prototype.onceSync=function(t,n){return n.sync=!0,this.once(t,n)},i.prototype.onceAsync=function(t,n){return n.async=!0,this.once(t,n)},i.prototype.removeListener=function(t,n){return this._eventListeners[t]instanceof Array&&(this._eventListeners[t]=this._eventListeners[t].filter(function(e){return e===n?(this.emitSync("removeListener",n),!1):!0}.bind(this))),this._oneTimeListeners[t]instanceof Array&&(this._oneTimeListeners[t]=this._oneTimeListeners[t].filter(function(e){return e===n?(this.emitSync("removeListener",n),!1):!0}.bind(this))),this},i.prototype.removeAllListeners=function(t){return t?(this._eventListeners[t]instanceof Array&&(this._eventListeners[t].forEach(function(e){this.emitSync("removeListener",e)}.bind(this)),delete this._eventListeners[t]),this._oneTimeListeners[t]instanceof Array&&(this._oneTimeListeners[t].forEach(function(e){this.emitSync("removeListener",e)}.bind(this)),delete this._oneTimeListeners[t])):(Object.keys(this._eventListeners).forEach(function(e){this.removeAllListeners(e)}.bind(this)),Object.keys(this._oneTimeListeners).forEach(function(e){this.removeAllListeners(e)}.bind(this))),this},i.prototype.setMaxListeners=function(t){return this._maxListeners=t,this},i.prototype.listeners=function(t){var n=[];return this._eventListeners[t]instanceof Array&&Array.prototype.push.apply(n,this._eventListeners[t]),this._oneTimeListeners[t]instanceof Array&&Array.prototype.push.apply(n,this._oneTimeListeners[t]),n},i.listenerCount=function(t,n){var r=0;return t._eventListeners[n]instanceof Array&&(r+=t._eventListeners[n].length),t._oneTimeListeners[n]instanceof Array&&(r+=t._oneTimeListeners[n].length),r},t.exports=i})()},{"is-async":2}],2:[function(e,t,n){function r(e,t){return e.async||!e.sync&&e.length===t}t.exports=r},{}]},{},[1]);

@@ -7,3 +7,3 @@ {

"author": "David Ellis",
"version": "0.0.1",
"version": "0.0.2",
"bugs": "https://github.com/dfellis/async-cancelable-events/issues",

@@ -10,0 +10,0 @@ "repository": {

@@ -19,2 +19,10 @@ # async-cancelable-events

var EventEmitter = require('async-cancelable-events');
var util = require('util');
function MyEmittingObject() {
EventEmitter.call(this);
...
}
util.inherits(MyEmittingObject, EventEmitter);
```

@@ -28,3 +36,3 @@

2. The ``.on`` and ``.once`` methods try to "guess" if the provided handler is synchronous or asynchronous (based on its argument length), or can be explicitly registered as synchronous or asynchronous with ``.onSync``, ``.onAsync``, ``.onceSync``, ``.onceAsync``.
3. Did you know ``.addListener`` was a thing? I didn't. It's just a synonmym for ``.on``, by the way.
3. Passing the maximum number of listeners allowed will fire off a ``maxListenersPassed`` event with the event name and listener count as arguments. The warning the official ``EventEmitter`` prints is simply a listener for ``async-cancelable-events``, and can be disabled by running ``this.removeAllListeners('maxListenersPassed')`` just after the ``EventEmitter.call(this)`` listed above.
4. The various method calls are chainable, so ``foo.on('bar', func1).on('baz', func2)`` is valid.

@@ -31,0 +39,0 @@

@@ -137,5 +137,5 @@ var fs = require('fs');

bootstrap(test);
test.expect(12);
test.expect(15);
var emitter = new EventEmitter();
emitter.setMaxListeners(1);
emitter.setMaxListeners(2);
emitter.on('newListener', function(listener) {

@@ -146,3 +146,3 @@ test.ok(listener instanceof Function, 'got a new listener');

test.equal(eventName, 'someEvent', 'added too many listeners to someEvent');
test.equal(count, 2, "this town ain't big enough for the two of us!");
test.equal(count, 3, "this town ain't big enough for the two of us!");
});

@@ -158,2 +158,5 @@ emitter.on('removeListener', function(listener) {

});
emitter.once('someEvent', function() {
test.ok(true, 'third listener fired');
});
emitter.emit('someEvent', function() {

@@ -160,0 +163,0 @@ test.ok(true, 'event finished');

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc