Created
August 22, 2011 10:48
-
-
Save Gozala/1162121 to your computer and use it in GitHub Desktop.
Base idea behind streamer.
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
// 1. Node code | |
function sphagetti(name, callback) { | |
db.loadUser(name, function onUser(error, user) { | |
if (error) return callback(error) | |
db.query('SELECT * FROM store WHERE owner=?', user, function onQuery(error, items) { | |
if (error) return callback(error) | |
doSomething(items, callback) | |
}) | |
}) | |
} | |
// 2. Node without nesting | |
function user(name, callback) { | |
db.loadUser(name, callback) | |
} | |
function items(error, name, callback) { | |
if (error) return callback(error) | |
db.query('SELECT * FROM store WHERE owner=?', user, callback); | |
} | |
function sphagetti(name, callback) { | |
items(user(name), function onItems(error, items) { | |
if (error) return callback(error) | |
callback(doSomething(items)) | |
} | |
} | |
// 3. Let's invert a flow | |
function user(name) { | |
return function(succes, fail) { db.getUser(name, succes, fail) } | |
} | |
function query(SQL, user) { | |
return function(succes, fail) { | |
user(function(user) { db.query(SQL, user, succes, fail) }) | |
} | |
} | |
function Do(action, items) { | |
return function (success, fail) { | |
items(function(items) { success(action(items)) }, fail) | |
} | |
} | |
function items(name) { | |
return query('SELECT * FROM store WHERE owner=?', user(name)) | |
} | |
function sphagetti(name) { | |
var myUser = user(name) | |
var myItems = items(myUser) | |
return Do(doSomething, myItems) | |
} | |
// 4. magic ? | |
function $(action) { | |
return function() { | |
var args = Array.prototype.slice.call(arguments) | |
return function (succes, fail) { | |
var failure, tasks = args.slice(), values = [] | |
function callback(error) { | |
if (error) fail(error) | |
else succes.apply(null, Array.prototype.slice.call(arguments, 1)) | |
} | |
!function next(error, value) { | |
if (failure) return null | |
if (error) return fail(failure = error) | |
values.push(value) | |
if (!tasks.length) return action.apply(null, values.concat[[callback]])) | |
var task = tasks.shift() | |
typeof(task) === 'function' ? task(next) : next(null, tasks) | |
}(null, this) | |
} | |
} | |
} | |
function spaghetti(name) { | |
var user = $(db.loadUser)(name) | |
var items = $(db.query)('SELECT * FROM store WHERE owner=?', myUser) | |
return $(doSomething)(myItems) | |
} | |
// 5. What if base layer was like $ ? | |
function spaghetti(name) { | |
var user = db.getUser(name) | |
var items = db.query('SELECT * FROM store WHERE owner=?', user) | |
return doSomething(items) | |
} | |
Array.prototype.slice(arguments) should be Array.prototype.slice.call(arguments).
Yep thanks for pointing that out!
[].slice.call(arguments) is faster, especially when there will be a long scope chain lookup for Array
I thought creating a new array was more expensive. Regardless this code just illustrates idea so perf is not really important.
@michaelficarra Is the last paragraph question ?
If so, yes you can do it of course, it just point I'm trying to make is that, writing code like this:
function(a, b, callback) { ... }
quickly becomes unmanageable, in contrast to:
function(a, b) { return function callback() { .... } }
which is composition friendly.
In any case don't take this too seriously, I'm just playing with this idea ;)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Array.prototype.slice(arguments)
should beArray.prototype.slice.call(arguments)
. And[].slice.call(arguments)
is faster, especially when there will be a long scope chain lookup forArray
. Also: