Skip to content

Instantly share code, notes, and snippets.

@gmalysa
Last active December 17, 2015 08:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gmalysa/5581882 to your computer and use it in GitHub Desktop.
Save gmalysa/5581882 to your computer and use it in GitHub Desktop.
Quick benchmark test for comparing flux-link to some standard async packages that are commonly used
Results:
Promise overhead (calling one after another) x1000:
1: 65ms Base (plain Node.js lstat call)
2: 75ms When: Dedicated wrapper
3: 86ms flux-link
4: 97ms Deferred: Dedicated wrapper
5: 102ms Deferred: Promisify (generic wrapper)
6: 135ms jQuery.Deferred: Dedicated wrapper
7: 1055ms Q: Dedicated wrapper
8: 1538ms Q: nbind (generic wrapper)
Source code is based on https://github.com/medikoo/deferred/blob/master/benchmark/one-after-another.js,
modified to include a test for flux-link. Tests were run on an amazon EC2 micro instance (hence the short
duration to avoid cpu throttling). Repeated tests show that there is not much total difference between
deferred, when, and flux-link, with the order changing from time to time and run times varying from
70-120 ms for each. If you want/can re-run on a server that does not have throttling concerns to do tests
of a longer duration, that'd be great.
'use strict';
// Benchmark comparing overhead introduced by promise implementations
// (one by after another)
// To run it, do following in package path:
//
// $ npm install Q jquery when flux-link
// $ node benchmark/one-after-another.js
var forEach = require('es5-ext/lib/Object/for-each')
, pad = require('es5-ext/lib/String/prototype/pad')
, lstat = require('fs').lstat
, Q = require('Q')
, jqDeferred = require('jquery').Deferred
, when = require('when')
, deferred = require('../lib')
, fl = require('flux-link')
, now = Date.now
, Deferred = deferred.Deferred, promisify = deferred.promisify
, nextTick = process.nextTick
, self, time, count = 1000, data = {}, next, tests, def = deferred();
console.log("Promise overhead (calling one after another)",
"x" + count + ":\n");
tests = [function () {
var i = count;
self = function () {
lstat(__filename, function (err, stats) {
if (err) {
throw err;
}
if (--i) {
self(stats);
} else {
data["Base (plain Node.js lstat call)"] = now() - time;
next();
}
});
};
time = now();
self();
}, function () {
var i = count, dlstat;
dlstat = function (path) {
var def = new Deferred();
lstat(path, function (err, stats) {
def.resolve(err || stats);
});
return def.promise;
};
self = function () {
dlstat(__filename).end(function (stats) {
if (--i) {
self(stats);
} else {
data["Deferred: Dedicated wrapper"] = now() - time;
next();
}
});
};
time = now();
self();
}, function () {
var i = count, dlstat = promisify(lstat);
self = function () {
dlstat(__filename).end(function (stats) {
if (--i) {
self(stats);
} else {
data["Deferred: Promisify (generic wrapper)"] = now() - time;
next();
}
});
};
time = now();
self();
}, function () {
var i = count, dlstat;
dlstat = function (path) {
var def = Q.defer();
lstat(path, function (err, stats) {
if (err) {
def.reject(err);
} else {
def.resolve(stats);
}
});
return def.promise;
};
self = function () {
dlstat(__filename).then(function (stats) {
if (--i) {
self(stats);
} else {
data["Q: Dedicated wrapper"] = now() - time;
// Get out of try/catch clause
nextTick(next);
}
}).done();
};
time = now();
self();
}, function () {
var i = count, dlstat = Q.nbind(lstat, null);
self = function () {
dlstat(__filename).then(function (stats) {
if (--i) {
self(stats);
} else {
data["Q: nbind (generic wrapper)"] = now() - time;
// Get out of try/catch clause
nextTick(next);
}
}).done();
};
time = now();
self();
}, function () {
var i = count, dlstat;
dlstat = function (path) {
var def = jqDeferred();
lstat(path, function (err, stats) {
if (err) {
def.reject(err);
} else {
def.resolve(stats);
}
});
return def;
};
self = function () {
dlstat(__filename).done(function (stats) {
if (--i) {
self(stats);
} else {
data["jQuery.Deferred: Dedicated wrapper"] = now() - time;
next();
}
}).fail(function (e) {
throw e;
});
};
time = now();
self();
}, function () {
var i = count, dlstat;
dlstat = function (path) {
var def = when.defer();
lstat(path, function (err, stats) {
if (err) {
def.reject(err);
} else {
def.resolve(stats);
}
});
return def.promise;
};
self = function () {
dlstat(__filename).then(function (stats) {
if (--i) {
self(stats);
} else {
data["When: Dedicated wrapper"] = now() - time;
nextTick(next);
}
}, function (e) {
nextTick(function () {
throw e;
});
});
};
time = now();
self();
}, function() {
var i = count, env;
var chain = new fl.Chain();
function dlstat(env, after, stats) {
// $check does the same error checking on the first argument and only passes the remaining
// arguments if it is false-like, otherwise an exception is thrown
lstat(env.path, env.$check(after));
};
for (i = count; i > 0; --i) {
chain.push(dlstat);
}
env = new fl.Environment({}, console.log);
time = now();
env.path = __filename;
chain.call(null, env, function() {
data["flux-link"] = now() - time;
nextTick(next);
}, {});
}];
next = function () {
if (tests.length) {
tests.shift()();
} else {
def.resolve();
forEach(data, function (value, name, obj, index) {
console.log(index + 1 + ":", pad.call(value, " ", 5) + "ms ", name);
}, null, function (a, b) {
return this[a] - this[b];
});
}
};
next();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment