Skip to content

Instantly share code, notes, and snippets.

@munro
Created July 19, 2011 21:16
Show Gist options
  • Save munro/1093738 to your computer and use it in GitHub Desktop.
Save munro/1093738 to your computer and use it in GitHub Desktop.
Async join comparison with TameJS
var db = {
get: function (key, callback) {
setTimeout(function () {
callback(false, 'got ' + key);
}, Math.floor(Math.random() * 1000));
}
},
helpers = require('./2_helpers');
// Here is a similar blocking example of what the following algorithms are doing:
// var sum = db.get('a') + db.get('b') + db.get('c');
(function tamejs() {
var errs = [], values = [];
twait {
db.get('a', mkevent(errs[0], values[0]));
db.get('b', mkevent(errs[1], values[1]));
db.get('c', mkevent(errs[2], values[2]));
}
console.log('tamejs:\n ' + values.join('\n '));
}()); // 7 lines of code
(function vanilla_unordered() {
var count = 0, values = [];
function defer(err, value) {
values.push(value);
if ((count += 1) === 3) {
console.log('vanilla unordered:\n ' + values.join('\n '));
}
}
db.get('a', defer);
db.get('b', defer);
db.get('c', defer);
}()); // 10 lines of code
(function vanilla_ordered() {
var count = 0, values = [];
function defer(index) {
return function (err, value) {
values[index] = value;
if ((count += 1) === 3) {
console.log('vanilla ordered:\n ' + values.join('\n '));
}
};
}
db.get('a', defer(0));
db.get('b', defer(1));
db.get('c', defer(2));
}()); // 12 lines of code
// Examples that use helper functions
(function vanilla_asyncMap() {
['a', 'b', 'c'].asyncMap(function (value, callback) {
db.get(value, callback);
}, function (err, values) {
console.log('vanilla_asyncMap:\n ' + values.join('\n '));
});
}()); // 5 lines of code
(function vanilla_decorated() {
var values = [], each;
each = helpers.decorators.defer(function (err, value) {
values.push(value);
if (each.done()) {
console.log('vanilla_decorated:\n ' + values.join('\n '));
}
});
db.get('a', each.defer());
db.get('b', each.defer());
db.get('c', each.defer());
}()); // 10 lines of code
// vim: sw=4 ts=4 sts=4 et:
var helpers = require('./2_helpers'),
COUNT = 1000000,
db = {
get: function (key, callback) {
callback(false, 'got ' + key);
}
};
// Here is a similar blocking example of what the following algorithms are doing:
// var i, sum = 0;
// for(i = 0; i < COUNT; i += 1) {
// sum += db.get('defer ' + i);
// }
console.time('tamejs');
(function tamejs() {
var errs = [], values = [];
twait {
for (var i = 0; i < COUNT; i += 1) {
(function (i) {
db.get('defer ' + i, mkevent(errs[i], values[i]));
}(i));
}
}
console.timeEnd('tamejs'); // 1000000 @ 1104ms
console.log('tamejs:', values.join().length);
}()); // 10 lines of code
console.time('vanilla_unordered');
(function vanilla_unordered() {
var i, count = 0, errs = [], values = [];
function defer(err, value) {
errs.push(err);
values.push(value);
if ((count += 1) === COUNT) {
console.timeEnd('vanilla_unordered'); // 1000000 @ 541ms
console.log('vanilla_unordered:', values.join().length);
}
}
for (i = 0; i < COUNT; i += 1) {
db.get('defer ' + i, defer);
}
}()); // 12 lines of code
console.time('vanilla_ordered');
(function vanilla_ordered() {
var i, count = 0, errs = [], values = [];
function defer(index) {
return function (err, value) {
errs[index] = err;
values[index] = value;
if ((count += 1) === COUNT) {
console.timeEnd('vanilla_ordered'); // 1000000 @ 766ms
console.log('vanilla_ordered:', values.join().length);
}
};
}
for (i = 0; i < COUNT; i += 1) {
db.get('defer ' + i, defer(i));
}
}()); // 14 lines of code
// Examples that use helper functions
console.time('vanilla_asyncMap');
(function vanilla_asyncMap() {
var keys = [];
for (i = 0; i < COUNT; i+= 1) {
keys.push('defer ' + i);
}
keys.asyncMap(function (value, callback) {
db.get(value, callback);
}, function (err, values) {
console.timeEnd('vanilla_asyncMap'); // 1000000 @ 816ms
console.log('vanilla_asyncMap:', values.join().length);
});
}()); // 10 lines of code
console.time('vanilla_decorated');
(function vanilla_decorated() {
var values = [], each;
each = helpers.decorators.defer(function (err, value) {
values.push(value);
if (each.done()) {
console.timeEnd('vanilla_decorated'); // 1000000 @ 5603ms
console.log('vanilla_decorated:', values.join().length);
}
});
for (i = 0; i < COUNT; i += 1) {
db.get('defer ' + i, each.defer());
}
}()); // 11 lines of code
// vim: sw=4 ts=4 sts=4 et:
Array.prototype.asyncMap = function (fn, callback) {
var that = this, i, count = 0, errors = [], map = [];
for (i = 0; i < this.length; i += 1) {
(function iter(i) {
fn(that[i], function (err, value) {
err && errors.push(err);
map[i] = value;
if ((count += 1) === that.length) {
callback(errors.length ? errors : false, map);
}
});
}(i));
}
};
exports.decorators = {
defer: function (fn) {
var wrapped = fn;
// The decorated function has to be defered otherwise if fn.defer() is
// called immediately the decorated function will think it's done.
fn = function () {
var args = arguments;
setTimeout(function () {
wrapped.apply(false, args);
}, 0);
};
fn.__count = 0;
fn.__max = 0;
fn.defer = function () {
fn.__max += 1;
return fn;
};
fn.done = function () {
return (fn.__count += 1) === fn.__max;
};
return fn;
}
};
// vim: sw=4 ts=4 sts=4 et:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment