Skip to content

Instantly share code, notes, and snippets.

@jrydberg
Created May 3, 2011 18:52
Show Gist options
  • Save jrydberg/953962 to your computer and use it in GitHub Desktop.
Save jrydberg/953962 to your computer and use it in GitHub Desktop.
Twisted-style Deferreds in CoffeeScript
exports.AlreadyCalledError = class AlreadyCalledError
exports.Failure = class Failure
constructor: (@error) ->
check: (errorType) ->
if @error instanceof errorType
@error
else
null
toString: ->
"Failure: #{ @error }"
_isFailure = (obj) ->
obj instanceof Failure
_isDeferred = (obj) ->
obj instanceof Deferred
exports.Deferred = class Deferred
constructor: ->
@_callbacks = []
@_called = false
@_pauseLevel = 0
addCallbacks: (callback, errback, callbackArgs, errbackArgs) ->
callbackArgs = [] if not callbackArgs?
errbackArgs = [] if not errbackArgs?
@_callbacks.push [callback, errback, callbackArgs, errbackArgs]
this._runCallbacks() if @_called
return @
addCallback: (callback, args...) ->
this.addCallbacks callback, null, args, null
addErrback: (errback, args...) ->
this.addCallbacks null, errback, null, args
addBoth: (callback, args...) ->
this.addCallbacks callback, callback, args, args
_pause: ->
@_pauseLevel++
_unpause: ->
@_pauseLevel--
this._runCallbacks() if not @_pauseLevel and @_called
_continue: (@_result) ->
this._unpause()
_runCallbacks: ->
if not @_pauseLevel
[cb, @_callbacks] = [@_callbacks, []]
while cb.length != 0
item = cb.shift()
if _isFailure @_result
[callback, args] = [item[1], item[3]]
else
[callback, args] = [item[0], item[2]]
if callback
args.unshift @_result
try
@_result = callback.apply null, args
if _isDeferred @_result
@_callbacks = cb
this._pause()
@_result.addBoth (r) ->
this._continue r
break
catch e
@_result = new Failure e
_startRunCallbacks: (result) ->
throw new AlreadyCalledError() if @_called
@_called = true
@_result = result
this._runCallbacks()
callback: (result) ->
this._startRunCallbacks result
errback: (error) ->
error = new Failure(error) if not _isFailure error
this._startRunCallbacks error
exports.success = success = (result) ->
d = new Deferred()
d.callback result
return d
exports.fail = fail = (error) ->
d = new Deferred()
d.errback result
return d
(success "result").addCallback (result) =>
console.log "GOT RESULT", result
throw "ERROR"
.addErrback (error) =>
console.log "ERROR", error
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment