This post was originally published on Engineering@TelenorDigital.

I have been writing mostly C and C++ in the last months, hacking away on LoRa and drones, but I had the pleasure of doing a week of JavaScript again, and I was reminded how much I love this weird, quirk and beautiful language. So today a write-up of some very useful patterns that show the power of JS.

One-line async queue

Sometimes I want to run a number of functions in series, and don’t want to get a fully fledged library like async. We use this f.e. in Firefox OS test scripts to emulate sending keystrokes. This is easily done in a JavaScript one-liner.

var cmds = [
  function(callback) { console.log('a'), setTimeout(callback, 1000); },
  function(callback) { console.log('b'), setTimeout(callback, 300); }
];

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

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

If you’re using a function that returns a promise (like sendKey in FxOS), you can use this function as well…

var input = 'sometext'
var cmds = input.split('').map(function(char) {
  return function(next) {
    sendKey(char).then(next, next);
  };
});

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

One-line event emitter

In a similar fashion, although I like writing evented code I don’t feel like pulling in a full library like EventEmitter2. A neat little thing about JS in the browser is that every DOM element is already implementing DOM Level 3 events. So behold: a one line event emitter:

function createEventEmitter() {
  return document.createElement('div');
}

var ee = createEventEmitter();
ee.addEventListener('awesome', function(e) {
  console.log('received awesome!', e.detail);
});
ee.dispatchEvent(new CustomEvent('awesome', { detail: 1337 }));

Downsides:

  • 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" })

Function logger

Every now and then I’ll get thrown into a codebase where I’m unfamiliar, and I want to get a grasp of how code flows. In the past I used trace.gl, but it has been discontinued, so I’m rather tracing the flow of code by hand. This simple logger logs the name of the function and the arguments being passed in.

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 just put the following one-liner in every function you want to trace:

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

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

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

Promisify’ing functions

I like promises, but not everyone has seen the light, so I run into code that does not utilize them yet. Nice thing is that it’s easy to wrap node callbacks into promisified code without the need for an external library.

function wrap(fn, that) {
  var self = this;
  return function() {
    var args = [].slice.call(arguments);
    return new Promise(function(res, rej) {
      args.push(function(err, result) {
        if (err) return rej(err);
        res(result);
      });
      fn.apply(that || self, args);
    });
  };
}

function oldStyleFn(name, callback) {
  setTimeout(function() {
    callback(null, 'Hello ' + name);
  }, 1000);
}

wrap(oldStyleFn)('Jan').then(function(msg) {
  console.log(msg);
});

You can set the this context inside the wrapped function, by passing the context as second parameter to the wrap function.

Using .forEach(), .sort() on NodeList’s

There’s a ton of Array-like objects when dealing with the DOM, e.g. results from querySelectorAll or the FileList object. Even though the look like arrays, and have a length property, they are not proper arrays. That means functions like forEach, map, and sort are not working on them. We can cast them into proper arrays with a simple function:

var arr = [].slice.call(document.querySelectorAll('.div'));
typeof arr.forEach;
// function

From ES6 there’ll also be Array.from.