Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Change implementation to be modular #2

Closed
wants to merge 1 commit into from

2 participants

@KenPowers

This changes smokesignals to be modular in such a fashion that the same file can be loaded by CommonJS (node's require), AMD (RequireJS), or just included on a page.

@bentomas
Owner

Hey good idea! Unfortunately, I'm not going to make the file any bigger for the people directly including it. Goal number 2 is to be as small as possible, and this makes it quite a big bigger (by 40%). I've tried very hard to make it as small as I possibly can, and won't be accepting any changes to the minified version that either A) don't make it smaller, or B) don't fix bugs.

I would, however, consider allowing another two files to be added (in addition to smokesignals.js and smokesignals.min.js--maybe call them smokesignals.mod.js and smokesignals.mod.min.js) for people trying to include it with a loader of some sort. But the way you have done it isn't the most efficient size-wise. At the very least these lines from an older version of this library use fewer characters: https://github.com/bentomas/smokesignals/blob/c18e3f8f5aaaf996587db90413b4a1812359bf45/smokesignals.js#L1-L6
(I saw no reason to check for the amd property since for the module check in the previous section we cannot do any additional checking either).

If you want to code that up , I'd merge that! Maybe also remove all the comments from this new file and have a comment pointing them to the canonical version of the lib (smokesignals.js).

Thanks for being interested in making this library better and more versatile!

@bentomas bentomas closed this
@KenPowers

Just curious, if you previously supported AMD why did you remove it?

@bentomas
Owner

Woops! Somehow missed this comment last month!

To make the library considerably smaller. And no one complained.

Plus module loaders like that seem anathema to the philosophy of making libraries as small as possible. The require.js file is 14.6KB minified or 9.5 gzipped. That's a lot of page weight for something that can be fairly easily done with a simple <script src=""></script> and a precompiler. I'm not saying they aren't useful, I'm just saying I wasn't willing to sacrifice the goals of this project to support them.

But like I said, I'd be happy to add another file to the project which adds that functionality.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Dec 30, 2012
  1. @KenPowers
This page is out of date. Refresh to see the latest.
View
2  README.md
@@ -10,7 +10,7 @@ the functionality that Node's event emitter has.)
This library has three goals:
1. Make it easy and intuitive to listen for and initiate events on an object.
-2. Be really small. Right now the minified version comes in at 407 bytes (247
+2. Be really small. Right now the minified version comes in at 571 bytes (345
bytes gzipped).
3. Not pollute the global namespace or the objects it modifies with a bunch of
crap. I define crap as anything that is not the API.
View
18 index.js
@@ -1,18 +0,0 @@
-var existed = false;
-var old;
-
-if ('smokesignals' in global) {
- existed = true;
- old = global.smokesignals;
-}
-
-require('./smokesignals');
-
-module.exports = smokesignals;
-
-if (existed) {
- global.smokesignals = old;
-}
-else {
- delete global.smokesignals;
-}
View
2  package.json
@@ -7,7 +7,7 @@
, "email": "benjamin@benjaminthomas.org"
}
, "keywords": ["events", "emitter", "trigger"]
-, "main": "./index.js"
+, "main": "./smokesignals.min.js"
, "repository": {"type": "git", "url": "git://github.com/bentomas/smokesignals.git"}
, "scripts": { "test": "node ./test.js" }
}
View
150 smokesignals.js
@@ -1,82 +1,92 @@
-// in a few cases we've chosen optimizing script length over efficiency of code.
-// I think that is the right choice for this library. If you're adding and
-// triggering A LOT of events, you might want to use a different library.
-smokesignals = {
- convert: function(obj, handlers) {
- // we store the list of handlers as a local variable inside the scope
- // so that we don't have to add random properties to the object we are
- // converting. (prefixing variables in the object with an underscore or
- // two is an ugly solution)
- // we declare the variable in the function definition to use two less
- // characters (as opposed to using 'var '). I consider this an inelegant
- // solution since smokesignals.convert.length now returns 2 when it is
- // really 1, but doing this doesn't otherwise change the functionallity of
- // this module, so we'll go with it for now
- handlers = {};
+(function (name, global, definition) {
+ if (typeof module !== 'undefined') {
+ module.exports = definition();
+ } else if (typeof define !== 'undefined' && typeof define.amd === 'object') {
+ define(definition);
+ } else {
+ global[name] = definition();
+ }
+})('smokesignals', this, function () {
+ // in a few cases we've chosen optimizing script length over efficiency of code.
+ // I think that is the right choice for this library. If you're adding and
+ // triggering A LOT of events, you might want to use a different library.
+ return {
+ convert: function(obj, handlers) {
+ // we store the list of handlers as a local variable inside the scope
+ // so that we don't have to add random properties to the object we are
+ // converting. (prefixing variables in the object with an underscore or
+ // two is an ugly solution)
+ // we declare the variable in the function definition to use two less
+ // characters (as opposed to using 'var '). I consider this an inelegant
+ // solution since smokesignals.convert.length now returns 2 when it is
+ // really 1, but doing this doesn't otherwise change the functionallity of
+ // this module, so we'll go with it for now
+ handlers = {};
- // add a listener
- obj.on = function(eventName, handler) {
- // either use the existing array or create a new one for this event
- // this isn't the most efficient way to do this, but is the shorter
- // than other more efficient ways, so we'll go with it for now.
- (handlers[eventName] = handlers[eventName] || [])
- // add the handler to the array
- .push(handler);
+ // add a listener
+ obj.on = function(eventName, handler) {
+ // either use the existing array or create a new one for this event
+ // this isn't the most efficient way to do this, but is the shorter
+ // than other more efficient ways, so we'll go with it for now.
+ (handlers[eventName] = handlers[eventName] || [])
+ // add the handler to the array
+ .push(handler);
- return obj;
- }
-
- // add a listener that will only be called once
- obj.once = function(eventName, handler) {
- // create a wrapper listener, that will remove itself after it is called
- function wrappedHandler() {
- // remove ourself, and then call the real handler with the args
- // passed to this wrapper
- handler.apply(obj.off(eventName, wrappedHandler), arguments);
+ return obj;
}
- // in order to allow that these wrapped handlers can be removed by
- // removing the original function, we save a reference to the original
- // function
- wrappedHandler.h = handler;
- // call the regular add listener function with our new wrapper
- return obj.on(eventName, wrappedHandler);
- }
+ // add a listener that will only be called once
+ obj.once = function(eventName, handler) {
+ // create a wrapper listener, that will remove itself after it is called
+ function wrappedHandler() {
+ // remove ourself, and then call the real handler with the args
+ // passed to this wrapper
+ handler.apply(obj.off(eventName, wrappedHandler), arguments);
+ }
+ // in order to allow that these wrapped handlers can be removed by
+ // removing the original function, we save a reference to the original
+ // function
+ wrappedHandler.h = handler;
- // remove a listener
- obj.off = function(eventName, handler) {
- // loop through all handlers for this eventName, assuming a handler
- // was passed in, to see if the handler passed in was any of them so
- // we can remove it
- // it would be more efficient to stash the length and compare i
- // to that, but that is longer so we'll go with this.
- for (var list = handlers[eventName], i = 0; handler && list && list[i]; i++) {
- // either this item is the handler passed in, or this item is a
- // wrapper for the handler passed in. See the 'once' function
- list[i] != handler && list[i].h != handler ||
- // remove it!
- list.splice(i--,1);
+ // call the regular add listener function with our new wrapper
+ return obj.on(eventName, wrappedHandler);
}
- // if i is 0 (i.e. falsy), then there are no items in the array for this
- // event name (or the array doesn't exist)
- if (!i) {
- // remove the array for this eventname (if it doesn't exist then
- // this isn't really hurting anything)
- delete handlers[eventName];
+
+ // remove a listener
+ obj.off = function(eventName, handler) {
+ // loop through all handlers for this eventName, assuming a handler
+ // was passed in, to see if the handler passed in was any of them so
+ // we can remove it
+ // it would be more efficient to stash the length and compare i
+ // to that, but that is longer so we'll go with this.
+ for (var list = handlers[eventName], i = 0; handler && list && list[i]; i++) {
+ // either this item is the handler passed in, or this item is a
+ // wrapper for the handler passed in. See the 'once' function
+ list[i] != handler && list[i].h != handler ||
+ // remove it!
+ list.splice(i--,1);
+ }
+ // if i is 0 (i.e. falsy), then there are no items in the array for this
+ // event name (or the array doesn't exist)
+ if (!i) {
+ // remove the array for this eventname (if it doesn't exist then
+ // this isn't really hurting anything)
+ delete handlers[eventName];
+ }
+ return obj;
}
- return obj;
- }
- obj.emit = function(eventName) {
- // loop through all handlers for this event name and call them all
- // it would be more efficient to stash the length and compare i
- // to that, but that is longer so we'll go with this.
- for(var list = handlers[eventName], i = 0; list && list[i];) {
- list[i++].apply(obj, list.slice.call(arguments, 1));
+ obj.emit = function(eventName) {
+ // loop through all handlers for this event name and call them all
+ // it would be more efficient to stash the length and compare i
+ // to that, but that is longer so we'll go with this.
+ for(var list = handlers[eventName], i = 0; list && list[i];) {
+ list[i++].apply(obj, list.slice.call(arguments, 1));
+ }
+ return obj;
}
+
return obj;
}
-
- return obj;
}
-}
+});
View
2  smokesignals.min.js
@@ -1 +1 @@
-smokesignals={convert:function(c,e){e={};c.on=function(d,a){(e[d]=e[d]||[]).push(a);return c};c.once=function(d,a){function b(){a.apply(c.off(d,b),arguments)}b.h=a;return c.on(d,b)};c.off=function(d,a){for(var b=e[d],f=0;a&&b&&b[f];f++)b[f]!=a&&b[f].h!=a||b.splice(f--,1);f||delete e[d];return c};c.emit=function(d){for(var a=e[d],b=0;a&&a[b];)a[b++].apply(c,a.slice.call(arguments,1));return c};return c}};
+(function(n,e,t){typeof module!="undefined"?module.exports=t():typeof define!="undefined"&&typeof define.amd=="object"?define(t):e[n]=t()})("smokesignals",this,function(){return{convert:function(n,e){return e={},n.on=function(t,o){return(e[t]=e[t]||[]).push(o),n},n.once=function(e,t){function o(){t.apply(n.off(e,o),arguments)}return o.h=t,n.on(e,o)},n.off=function(t,o){for(var f=e[t],u=0;o&&f&&f[u];u++)f[u]!=o&&f[u].h!=o||f.splice(u--,1);return u||delete e[t],n},n.emit=function(t){for(var o=e[t],f=0;o&&o[f];)o[f++].apply(n,o.slice.call(arguments,1));return n},n}}})
View
2  test.js
@@ -6,7 +6,7 @@ console.log('test do not pollute node globals when requiring');
globalKeys.push(key);
}
- var smokesignals = require('./index');
+ var smokesignals = require('./');
for (var key in global) {
assert.ok(globalKeys.indexOf(key) > -1);
Something went wrong with that request. Please try again.