Created
July 19, 2011 21:16
-
-
Save munro/1093738 to your computer and use it in GitHub Desktop.
Async join comparison with TameJS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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