Simple EventEmitter in one line in javascript nl

Door creator1988 op dinsdag 7 januari 2014 15:12 - Reacties (1)
Categorie: Frontend, Views: 5.903

Chances are that if you have a large javascript application that you'll need an EventEmitter at one moment or another because events are great to wire separate modules together without them having to expose implementation details. Too bad that you'll need to pull in dependencies, another library, extra risk, etc. Especially if you're testing some simple scenario or small app that's a lot of boilerplate. Behold: a dependency-less event emitter (1 line of javascript!):

JavaScript:
1
2
3
function createEventEmitter() {
  return document.createElement('div');
}


All DOM elements implement DOM Level 3 events, which you can abuse as a nice event emitter. Great thing is that you get cancelation and bubbling as well. Bad things:
  • It's about 5x times as slow as EventEmitter.js (source), but you can very easily swap out this by EE if required in a later stage.
  • Dispatching events is a bit cumbersome because you need to use this syntax: `new CustomEvent("eventname", { detail: "eventdetail" })`
Usage:

JavaScript:
1
2
3
4
5
var ee = document.createElement('div')
ee.addEventListener('awesome', function() { console.log('omg omg omg', e.detail) })
ee.dispatchEvent(new CustomEvent('awesome', { detail: 1337 }))
// omg omg omg, 1337 /* output from the console.log */
// true /* event did not get canceled */

Simple function logger in JS nl

Door creator1988 op maandag 6 januari 2014 12:57 - Reacties (4)
Categorie: Frontend, Views: 4.521

Every now and then I end up in a code base where I don't have a clue about the flow yet; like today when testing out the new keyboard application that we're developing for Firefox OS. To see whether the flow is actually sane I plug in a simple function logger that allows me to see which functions are called and with what arguments.

JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function log(args) {
    var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
    // stole this from http://stackoverflow.com/questions/1007981/how-to-get-function-parameter-names-values-dynamically-from-javascript
    function getParamNames(func) {
      var fnStr = func.toString().replace(STRIP_COMMENTS, '');
      var result = fnStr.slice(fnStr.indexOf('(')+1, fnStr.indexOf(')')).match(/([^\s,]+)/g);
      if(result === null)
         result = [];
      return result;
    }

    console.log(args.callee.name, getParamNames(args.callee).reduce(function(obj, k, ix) { 
      obj[k] = args[ix]; 
      return obj; 
    }, {}));
  }


Now you can take advantage of this by putting a call to this function on the first line of any function you want to trace:

JavaScript:
1
function a(b, c) { log(arguments); }


When calling the a function, it will log the function name and an object with argument names and values:

JavaScript:
1
2
a(4, 5);
// a { b: 4, c: 5 }


Remember to disable "use strict" because accessing callee is not permitted anymore.

Simple async queue in javascript nl

Door creator1988 op donderdag 2 januari 2014 13:51 - Reacties (2)
Categorie: Frontend, Views: 3.529

Normally I fall back to caolan's async module, but I'm not in a node.js environment and I needed a simple async queue with concurrency 1; which can be done in a one liner.

JavaScript:
1
2
3
4
5
6
7
8
9
10
var q = [ 
  function a(n) { console.log('a'), setTimeout(n, 30); },
  function b(n) { console.log('b'), setTimeout(n, 10); }
];

function queue(q, n) {
  q.length ? q.shift()(queue.bind(this, q, n)) : n();
}

queue(q, function() { console.log('done') });


You could use arguments.callee rather than queue to bind to the current function, but it has been deprecated since ES5.

It's also easy to use it with promises, let's say I have a function |sendKey| that returns a promise and I want to send a string char by char:

JavaScript:
1
2
3
4
5
6
7
8
var input = 'sometext'
var q = input.split('').map(function(c) {
  return function(n) {
    sendKey(c).then(n);
  };
});

queue(q, function() { console.log('done') });