A module for weak referenced callbacks with timeouts.


node-candle is a node.js module that brings a callback broker to your application. It's inspired by acknowledgements.

  • it assigns ids to callbacks. This allows to create request-response mechanism over any network module easily.
  • it can add timeouts to callbacks.
  • it makes callbacks weakly referenced. And after a callback is resolved or timed out it becomes free and is destroyed during next garbage collection. This feature aims to let you create leak-free applications. This feature is the contrary to addTimeout and future which can keep callbacks from deletion.
  • it's blazing fast and can do:
  • 1,000,000 add()+resolve() iterations per second;
  • 500,000 add()+setTimeout()+resolve() iterations per second.

A simple example

var Candle = require('candle');
// Create a new candle, usually you will need only one since it can handle many callbacks. 
var c = new Candle();
// Add a callback to it 
var id = c.add(function(errresponse) { console.log('callback fired,', !!err, response); })
// You can pass these ids over network and catch back along it with a response. 
// When you're ready just resolve the callback using these ids: 
c.resolve(id, null, 'whoa!');
// output: "callback fired, false whoa!" 

More examples. Also consider DEBUG=candle node script.js to better understand how it works.

A network example

Let's examine the following situation. We have 2 servers, Server1 and Server2, and we want to make some requests from Server1 to Server2 which is known that it has unpredictable response time:

socket.on('myrequest', function(payloadid) {
  // dont send anything at all about 'r3' 
  if (payload == 'r3') return;
  // send response after 10ms for 'r1', but after 1000ms for 'r2'. 
  var timeout = (payload == 'r1') ? 10 : 1000;
  setTimeout(function() {
    socket.emit('myresponse', id, payload + '_response');
  }, timeout);

So we would like to send the requests to the Server2 and wait for responses for at most 100ms.

var Candle = require('candle');
var c = new Candle();
var start =;
socket.on('myresponse', function(idresponse) {
  c.resolve(id, null, response);
var doSmthWithRequest = function(errrequest) {
  console.log('got', !!err, request, 'on', - start, 'th ms');
var id;
id = c.add(doSmthWithRequest);
c.setTimeout(id, 100);
socket.emit('myrequest', 'r1', id);
id = c.add(doSmthWithRequest);
c.setTimeout(id, 100);
socket.emit('myrequest', 'r2', id);
id = c.add(doSmthWithRequest);
c.setTimeout(id, 100);
socket.emit('myrequest', 'r3', id);

This code will likely output the following:

got false r1_response on 13 th ms
got true undefined on 102 th ms
got true undefined on 102 th ms

So we get the response and 2 timeouts right after 100ms passed. As far as the r2_response will be returned after timeout it will be completely ignored.


npm install candle


  • c = new Candle - create a new candle
  • id = c.add(callback) - add a callback to the candle. Assigned id is returned.
  • c.resolve(id, [args, ...]) - resolve a callback identified by id and pass custom args to it.
  • c.remove(id) - completely remove the callback.
  • c.setTimeout(id, timeout) - add a timeout timeout ms to a callback by id.
  • c.clearTimeout(id) - remove a timeout from a callback by id.
  • c.setTimeoutResolver(callback) - assign a custom candle-wide callback that will be used to resolve on timeout. Default behavior is function(id) { this.resolve(id, new Timeout()); }. Sometimes, e.g. when you use the candle with async.parallel, you may want to use something like this callback: function(id) { this.resolve(id, null, { status: 'timeout' }); } to avoid it look like an error.

Running tests

npm test

NB: don't forget to run npm install from the candle module directory or install it with npm install candle --dev to install test framework

Running benchmarks

node benchmark/...

NB: don't forget to run npm install from the candle module directory or install it with npm install candle --dev to install benchmark framework