Created
April 2, 2012 04:16
-
-
Save toriaezunama/2280685 to your computer and use it in GitHub Desktop.
#lua #deferred #jquery
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
--[[ | |
== Example use == | |
local Deferred = require( 'lib.deferred' ) | |
local unitOfProcessing = function( aDefer ) | |
local closure = function() aDefer:resolve( "hi there" ) end | |
timer.performWithDelay( 2000, closure ) | |
end | |
defer = Deferred.new( unitOfProcessing ) | |
-- Uncommenting this should result in the following done() s not being called | |
--defer:fail( function( aErrMsg ) | |
-- print( "Arrrge we failed with: " .. tostring( aErrMsg ) ) | |
--end ) | |
--defer:reject( "Error occured" ) | |
-- Should be called after 2 seconds | |
defer:done( function ( aParam1 ) | |
print( 'defer.done() works. ' .. tostring( aParam1 ) ) | |
end); | |
-- Already resolved in the previous done() (500ms earlier) so should trigger instantly | |
timer.performWithDelay( 2500, function() | |
defer:done( function( aParam1 ) | |
print( '(resolved) defer.done() works. ' .. tostring( aParam1 ) ) | |
end ) | |
end ); | |
]] | |
--== Built in functions | |
local assert = assert | |
local error = error | |
local pairs = pairs | |
local ipairs = ipairs | |
local print = print | |
local setmetatable = setmetatable | |
local tonumber = tonumber | |
local tostring = tostring | |
local type = type | |
local unpack = unpack | |
--== Built in lib | |
local string = string | |
local table = table | |
local timer = timer | |
--== Libs | |
--local Utils = require( 'lib.utils' ) | |
Utils = {} | |
Utils.concatArray = function( aSrc, aDst ) | |
for _, v in ipairs( aSrc ) do | |
aDst[ #aDst + 1 ] = v | |
end | |
end | |
--== Define what we want to be available in the sandbox | |
local Deferred = {} | |
setfenv( 1, Deferred ) | |
--== From here down we are in scope | |
Deferred.pending = "pending" | |
Deferred.resolved = "resolved" | |
Deferred.rejected = "rejected" | |
local mt_deferred = {} | |
-- Add handlers to be called when the Deferred object is either resolved or rejected. | |
--deferred.always() | |
-- Add handlers to be called when the Deferred object is resolved. | |
--[[ | |
The deferred.done() method accepts one or more arguments, all of which can be either a single function or an array of functions. When the Deferred is resolved, the doneCallbacks are called. Callbacks are executed in the order they were added. Since deferred.done() returns the deferred object, other methods of the deferred object can be chained to this one, including additional .done() methods. When the Deferred is resolved, doneCallbacks are executed using the arguments provided to the resolve or resolveWith method call in the order they were added. | |
]] | |
function mt_deferred:done( aDoneCallbacks ) | |
-- Defaults | |
aDoneCallbacks = aDoneCallbacks or {} | |
if "function" == type( aDoneCallbacks ) then | |
aDoneCallbacks = { aDoneCallbacks } | |
end | |
assert( "table" == type( aDoneCallbacks ) ) | |
if Deferred.pending == self.state then | |
Utils.concatArray( aDoneCallbacks, self.doneCallbacks ) | |
elseif Deferred.resolved == self.state then | |
-- Execute callbacks | |
for _, callback in ipairs( aDoneCallbacks ) do | |
callback( unpack( self.resolvedArgs ) ) | |
end | |
end | |
return self -- chainable | |
end | |
-- Add handlers to be called when the Deferred object is rejected. | |
function mt_deferred:fail( aRejectCallbacks ) | |
-- Defaults | |
aRejectCallbacks = aRejectCallbacks or {} | |
if "function" == type( aRejectCallbacks ) then | |
aRejectCallbacks = { aRejectCallbacks } | |
end | |
assert( "table" == type( aRejectCallbacks ) ) | |
if Deferred.pending == self.state then | |
Utils.concatArray( aRejectCallbacks, self.rejectCallbacks ) | |
elseif Deferred.resolved == self.state then | |
-- Execute callbacks | |
for _, callback in ipairs( aRejectCallbacks ) do | |
callback( unpack( self.rejectArgs ) ) | |
end | |
end | |
return self -- chainable | |
end | |
-- Reject a Deferred object and call any failCallbacks with the given args. | |
function mt_deferred:reject( ... ) | |
if Deferred.pending == self.state then | |
self.state = Deferred.rejected | |
self.rejectArgs = arg | |
-- Execute callbacks | |
for _, callback in ipairs( self.rejectCallbacks ) do | |
callback( unpack( arg ) ) | |
end | |
-- Empty arrays | |
self.doneCallbacks = {} | |
self.rejectCallbacks = {} | |
end | |
return self -- chainable | |
end | |
-- Resolve a Deferred object and call any doneCallbacks with the given args. | |
function mt_deferred:resolve( ... ) | |
if Deferred.pending == self.state then | |
self.state = Deferred.resolved | |
self.resolvedArgs = arg | |
-- Execute callbacks | |
for _, callback in ipairs( self.doneCallbacks ) do | |
callback( unpack( arg ) ) | |
end | |
-- Empty arrays | |
self.doneCallbacks = {} | |
self.rejectCallbacks = {} | |
end | |
return self -- chainable | |
end | |
-- Determine the current state of a Deferred object. | |
--[[ | |
"pending": The Deferred object is not yet in a completed state (neither "rejected" nor "resolved"). | |
"resolved": The Deferred object is in the resolved state, meaning that either deferred.resolve() or deferred.resolveWith() has been called for the object and the doneCallbacks have been called (or are in the process of being called). | |
"rejected": The Deferred object is in the rejected state, meaning that either deferred.reject() or deferred.rejectWith() has been called for the object and the failCallbacks have been called (or are in the process of being called). | |
This method is primarily useful for debugging to determine, for example, whether a Deferred has already been resolved even though you are inside code that intended to reject it. | |
]] | |
function mt_deferred:state() | |
return self.state | |
end | |
function new( aAsyncUnitOfProcessing ) | |
local def = { | |
state = Deferred.pending, | |
doneCallbacks = {}, | |
rejectCallbacks = {}, | |
} | |
setmetatable( def, { __index = mt_deferred } ) | |
-- Start the processing and pass in deferred object so that the unit of processing has access to deferred object's interface | |
aAsyncUnitOfProcessing( def ) | |
return def | |
end | |
return Deferred |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment