Skip to content

Instantly share code, notes, and snippets.

@strandel
Last active December 14, 2015 12:18
Show Gist options
  • Save strandel/5085114 to your computer and use it in GitHub Desktop.
Save strandel/5085114 to your computer and use it in GitHub Desktop.
Cancelable asynchronous chain
function chain() {
var queue = []
, withoutContext = null
function chainer(func) {
queue.push(func)
return chainer
}
chainer.run = function () {return run(queue)}
function run(queue /*, ...*/) {
if (queue.length === 0) return
var skipFirst = 1
, params = slice(arguments, skipFirst)
, restOfQueue = slice(queue, skipFirst)
, func = queue[0]
, ctx = {shouldContinue: true, cancel: function () {ctx.shouldContinue = false}}
if (isAsync(func, params)) {
func.apply(ctx, params.concat([doneCallback(ctx, restOfQueue)]))
} else {
var ret = func.apply(ctx, params)
if (ctx.shouldContinue) run(restOfQueue, ret)
}
}
// if function has more params than we are passing in, it has a 'done' param, thus is treated as asynchronous
function isAsync(func, params) {return func.length > params.length}
function slice(x, skipFromBeginning) {return Array.prototype.slice.call(x, skipFromBeginning)}
function doneCallback(ctx, queue) {return function (/*...*/) {
if (ctx.shouldContinue) run.apply(withoutContext, [queue].concat(slice(arguments)))
}}
return chainer
}
// Example
chain()
(just([1,3,5]))
(filter(even)) // <== as filter calls cancel(), the rest of the chain is not executed
(map(double))
(delayTwoSeconds)
(console.log)
.run()
// Details
function filter(func) {return function (arr) {
var result = arr.filter(func)
if (result.length === 0) this.cancel() // <== cancel the chain if no values are passed forward
return result
}}
function map(func) {return function (arr) {return arr.map(func)}}
function just(x) {return function () {return x}}
function even(x) {return x%2==0}
function double(x) {return x*2}
function print(x) {console.log(x)}
function delayTwoSeconds(arr, done) {setTimeout(function () {done(arr)}, 2000)}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment