Sichere Verwendung von Callbacks in Node.js

Beim asynchronen Programmieren kommt es oft darauf an, sicherzustellen das Callbacks auch tatsächlich zurückkommen bzw. nur ein einziges mal zurückkommen.

Um dieses Problem zu abstrahieren nutze ich selbst folgende Funktion:

function wrap(callback, timeout) {
  if (callback._timeoutId && callback._callback) {
    clearTimeout(callback._timeoutId);
    callback = callback._callback;
    return callback;
  }

  var returned = false;

  function onTimeout() {
    returned = true;
    var err = new Error('Timeout expired');
    err.code = 'EWRAPTO';
    callback(err);
  }

  var wrapper = function() {
    clearTimeout(wrapper._timeoutId);
    if (!returned) {
      var args = Array.prototype.slice.call(arguments);
      callback.apply({}, args);
    } else {
      throw new Error('Duplicate callback');
    }
  };

  wrapper._callback = callback;
  wrapper._timeoutId = setTimeout(onTimeout, timeout || 1000);

  return wrapper;
}

Die Verwendung ist wie folgt:

dns.lookup('www.joocom.de', wrap(function(err, address, family) {
  // Will be executed exactly one-time.
  // Either on return from dns.lookup(),
  //   or when the timeout of 1000ms expired.
}, 1000));

Viel Spaß!