Comparing version 0.0.4 to 0.1.0
533
index.js
(function(define){ | ||
define([], function(){ | ||
function _Deferred () { | ||
if ( !( this instanceof _Deferred ) ) return new _Deferred(); | ||
var callbacks = [], | ||
fired, | ||
firing, | ||
cancelled, | ||
deferred = this; | ||
this.done = function done (){ | ||
if ( !cancelled ) { | ||
var args = arguments, | ||
i = 0, | ||
elem, | ||
type, | ||
_fired; | ||
if ( fired ) { | ||
_fired = fired; | ||
fired = 0; | ||
} | ||
for ( ; elem = args[i++] ; ) { | ||
if ( typeof elem === "object" && elem instanceof Array ){ | ||
deferred.done.apply( deferred, elem ); | ||
} else if ( typeof elem === "function" ) { | ||
callbacks.push( elem ); | ||
} | ||
} | ||
if ( _fired ){ | ||
deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] ); | ||
} | ||
} | ||
return this; | ||
}; | ||
this.resolveWith = function resolveWith ( context, args ){ | ||
if ( !cancelled && !fired && !firing ) { | ||
args = args || []; | ||
firing = 1; | ||
try { | ||
while( callbacks[0] ) { | ||
callbacks.shift().apply( context, args ); | ||
} | ||
} finally { | ||
fired = [ context, args ]; | ||
firing = 0; | ||
} | ||
} | ||
return this; | ||
}; | ||
this.resolve = function resolve () { | ||
deferred.resolveWith( this, arguments ); | ||
return this; | ||
}; | ||
this.isResolved = function isResolved () { | ||
return !!( firing || fired ); | ||
}; | ||
this.cancel = function cancel (){ | ||
cancelled = 1; | ||
callbacks = []; | ||
return this; | ||
}; | ||
} | ||
var promiseMethods = "done fail isResolved isRejected promise then always pipe".split( " " ); | ||
var Deferred = function Deferred ( func ) { | ||
var deferred = _Deferred(), | ||
failDeferred = _Deferred(), | ||
promise; | ||
deferred.then = function then ( doneCallbacks, failCallbacks ) { | ||
deferred.done( doneCallbacks ).fail( failCallbacks ); | ||
return this; | ||
}; | ||
deferred.always = function always () { | ||
return deferred.done.apply( deferred, arguments ).fail.apply( this, arguments ); | ||
}; | ||
deferred.fail = failDeferred.done; | ||
deferred.rejectWith = failDeferred.resolveWith; | ||
deferred.reject = failDeferred.resolve; | ||
deferred.isRejected = failDeferred.isResolved; | ||
deferred.pipe = function pipe ( fnDone, fnFail ) { | ||
return Deferred(function( newDefer ){ | ||
var handles = { | ||
done : [fnDone, "resolve"], | ||
fail : [fnFail, "reject"] | ||
}; | ||
Object.keys( handles ).forEach( function( handler ){ | ||
var data = handles[handler], | ||
fn = data[0], | ||
action = data[1], | ||
returned; | ||
if ( typeof fn === "function" ) { | ||
deferred[ handler ](function(){ | ||
returned = fn.apply( this, arguments ); | ||
if ( returned && typeof returned.promise === "function" ) { | ||
returned.promise().then( newDefer.resolve, newDefer.reject ); | ||
} else { | ||
newDefer[ action ]( returned ); | ||
} | ||
}); | ||
} else { | ||
deferred[ handler ]( newDefer[ action ] ); | ||
} | ||
}, handles) | ||
}).promise(); | ||
}; | ||
deferred.promise = function ( obj ) { | ||
if ( obj == null ) { | ||
if ( promise ) { | ||
return promise; | ||
} | ||
promise = obj = {}; | ||
} | ||
promiseMethods.forEach(function(method){ | ||
this[ method ] = deferred[ method ]; | ||
}, obj); | ||
return obj; | ||
}; | ||
deferred.done( failDeferred.cancel ).fail( deferred.cancel ); | ||
delete deferred.cancel; | ||
if ( func ) { | ||
func.call( deferred, deferred ); | ||
} | ||
return deferred; | ||
} | ||
Deferred.when = function when ( firstParam ) { | ||
var args = arguments, | ||
i = 0, | ||
length = args.length, | ||
count = length, | ||
deferred = length <= 1 && firstParam && typeof firstParam.promise === "function" ? | ||
firstParam : | ||
Deferred(); | ||
function resolveFunc ( i ) { | ||
return function ( value ) { | ||
args[ i ] = arguments.length > 1 ? [].slice.call( arguments, 0 ) : value; | ||
if ( !( --count ) ) { | ||
deferred.resolveWith( deferred, [].slice.call( args, 0 ) ); | ||
} | ||
}; | ||
} | ||
if ( length > 1 ) { | ||
for ( ; i < length ; i++ ) { | ||
if ( args[ i ] && typeof args[ i ].promise === "function" ){ | ||
args[ i ].promise().then( resolveFunc(i), deferred.reject ); | ||
} else { | ||
--count; | ||
} | ||
} | ||
if ( !count ) { | ||
deferred.resolveWith( deferred, args ); | ||
} | ||
} else if ( deferred !== firstParam ) { | ||
deferred.resolveWith( deferred, length ? [ firstParam ] : [] ); | ||
} | ||
return deferred.promise(); | ||
} | ||
var isArray = function( elem ) { | ||
return typeof elem === "object" && elem instanceof Array; | ||
}; | ||
var isFunction = function ( fn ) { | ||
return typeof fn === "function"; | ||
}; | ||
var // Static reference to slice | ||
sliceDeferred = [].slice; | ||
// String to Object flags format cache | ||
var flagsCache = {}; | ||
// Convert String-formatted flags into Object-formatted ones and store in cache | ||
function createFlags( flags ) { | ||
var object = flagsCache[ flags ] = {}, | ||
i, length; | ||
flags = flags.split( /\s+/ ); | ||
for ( i = 0, length = flags.length; i < length; i++ ) { | ||
object[ flags[i] ] = true; | ||
} | ||
return object; | ||
} | ||
// Borrowed shamelessly from https://github.com/wookiehangover/underscore.Deferred | ||
var _each = function( obj, iterator, context ) { | ||
var key, i, l; | ||
if ( !obj ) { | ||
return; | ||
} | ||
if ( forEach && obj.forEach === forEach ) { | ||
obj.forEach( iterator, context ); | ||
} else if ( obj.length === +obj.length ) { | ||
for ( i = 0, l = obj.length; i < l; i++ ) { | ||
if ( i in obj && iterator.call( context, obj[i], i, obj ) === breaker ) { | ||
return; | ||
} | ||
} | ||
} else { | ||
for ( key in obj ) { | ||
if ( hasOwn.call( obj, key ) ) { | ||
if ( iterator.call( context, obj[key], key, obj) === breaker ) { | ||
return; | ||
} | ||
} | ||
} | ||
} | ||
}; | ||
var Callbacks = function( flags ) { | ||
// Convert flags from String-formatted to Object-formatted | ||
// (we check in cache first) | ||
flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {}; | ||
var // Actual callback list | ||
list = [], | ||
// Stack of fire calls for repeatable lists | ||
stack = [], | ||
// Last fire value (for non-forgettable lists) | ||
memory, | ||
// Flag to know if list is currently firing | ||
firing, | ||
// First callback to fire (used internally by add and fireWith) | ||
firingStart, | ||
// End of the loop when firing | ||
firingLength, | ||
// Index of currently firing callback (modified by remove if needed) | ||
firingIndex, | ||
// Add one or several callbacks to the list | ||
add = function( args ) { | ||
var i, | ||
length, | ||
elem, | ||
type, | ||
actual; | ||
for ( i = 0, length = args.length; i < length; i++ ) { | ||
elem = args[ i ]; | ||
if ( isArray(elem) ) { | ||
// Inspect recursively | ||
add( elem ); | ||
} else if ( isFunction(elem) ) { | ||
// Add if not in unique mode and callback is not in | ||
if ( !flags.unique || !self.has( elem ) ) { | ||
list.push( elem ); | ||
} | ||
} | ||
} | ||
}, | ||
// Fire callbacks | ||
fire = function( context, args ) { | ||
args = args || []; | ||
memory = !flags.memory || [ context, args ]; | ||
firing = true; | ||
firingIndex = firingStart || 0; | ||
firingStart = 0; | ||
firingLength = list.length; | ||
for ( ; list && firingIndex < firingLength; firingIndex++ ) { | ||
if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) { | ||
memory = true; // Mark as halted | ||
break; | ||
} | ||
} | ||
firing = false; | ||
if ( list ) { | ||
if ( !flags.once ) { | ||
if ( stack && stack.length ) { | ||
memory = stack.shift(); | ||
self.fireWith( memory[ 0 ], memory[ 1 ] ); | ||
} | ||
} else if ( memory === true ) { | ||
self.disable(); | ||
} else { | ||
list = []; | ||
} | ||
} | ||
}, | ||
// Actual Callbacks object | ||
self = { | ||
// Add a callback or a collection of callbacks to the list | ||
add: function() { | ||
if ( list ) { | ||
var length = list.length; | ||
add( arguments ); | ||
// Do we need to add the callbacks to the | ||
// current firing batch? | ||
if ( firing ) { | ||
firingLength = list.length; | ||
// With memory, if we're not firing then | ||
// we should call right away, unless previous | ||
// firing was halted (stopOnFalse) | ||
} else if ( memory && memory !== true ) { | ||
firingStart = length; | ||
fire( memory[ 0 ], memory[ 1 ] ); | ||
} | ||
} | ||
return this; | ||
}, | ||
// Remove a callback from the list | ||
remove: function() { | ||
if ( list ) { | ||
var args = arguments, | ||
argIndex = 0, | ||
argLength = args.length; | ||
for ( ; argIndex < argLength ; argIndex++ ) { | ||
for ( var i = 0; i < list.length; i++ ) { | ||
if ( args[ argIndex ] === list[ i ] ) { | ||
// Handle firingIndex and firingLength | ||
if ( firing ) { | ||
if ( i <= firingLength ) { | ||
firingLength--; | ||
if ( i <= firingIndex ) { | ||
firingIndex--; | ||
} | ||
} | ||
} | ||
// Remove the element | ||
list.splice( i--, 1 ); | ||
// If we have some unicity property then | ||
// we only need to do this once | ||
if ( flags.unique ) { | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
return this; | ||
}, | ||
// Control if a given callback is in the list | ||
has: function( fn ) { | ||
if ( list ) { | ||
var i = 0, | ||
length = list.length; | ||
for ( ; i < length; i++ ) { | ||
if ( fn === list[ i ] ) { | ||
return true; | ||
} | ||
} | ||
} | ||
return false; | ||
}, | ||
// Remove all callbacks from the list | ||
empty: function() { | ||
list = []; | ||
return this; | ||
}, | ||
// Have the list do nothing anymore | ||
disable: function() { | ||
list = stack = memory = undefined; | ||
return this; | ||
}, | ||
// Is it disabled? | ||
disabled: function() { | ||
return !list; | ||
}, | ||
// Lock the list in its current state | ||
lock: function() { | ||
stack = undefined; | ||
if ( !memory || memory === true ) { | ||
self.disable(); | ||
} | ||
return this; | ||
}, | ||
// Is it locked? | ||
locked: function() { | ||
return !stack; | ||
}, | ||
// Call all callbacks with the given context and arguments | ||
fireWith: function( context, args ) { | ||
if ( stack ) { | ||
if ( firing ) { | ||
if ( !flags.once ) { | ||
stack.push( [ context, args ] ); | ||
} | ||
} else if ( !( flags.once && memory ) ) { | ||
fire( context, args ); | ||
} | ||
} | ||
return this; | ||
}, | ||
// Call all the callbacks with the given arguments | ||
fire: function() { | ||
self.fireWith( this, arguments ); | ||
return this; | ||
}, | ||
// To know if the callbacks have already been called at least once | ||
fired: function() { | ||
return !!memory; | ||
} | ||
}; | ||
return self; | ||
}; | ||
var Deferred = function( func ) { | ||
var doneList = Callbacks( "once memory" ), | ||
failList = Callbacks( "once memory" ), | ||
progressList = Callbacks( "memory" ), | ||
state = "pending", | ||
lists = { | ||
resolve: doneList, | ||
reject: failList, | ||
notify: progressList | ||
}, | ||
promise = { | ||
done: doneList.add, | ||
fail: failList.add, | ||
progress: progressList.add, | ||
state: function() { | ||
return state; | ||
}, | ||
// Deprecated | ||
isResolved: doneList.fired, | ||
isRejected: failList.fired, | ||
then: function( doneCallbacks, failCallbacks, progressCallbacks ) { | ||
deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks ); | ||
return this; | ||
}, | ||
always: function() { | ||
deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments ); | ||
return this; | ||
}, | ||
pipe: function( fnDone, fnFail, fnProgress ) { | ||
return Deferred(function( newDefer ) { | ||
_each( { | ||
done: [ fnDone, "resolve" ], | ||
fail: [ fnFail, "reject" ], | ||
progress: [ fnProgress, "notify" ] | ||
}, function( handler, data ) { | ||
var fn = data[ 0 ], | ||
action = data[ 1 ], | ||
returned; | ||
if ( isFunction( fn ) ) { | ||
deferred[ handler ](function() { | ||
returned = fn.apply( this, arguments ); | ||
if ( returned && isFunction( returned.promise ) ) { | ||
returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify ); | ||
} else { | ||
newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); | ||
} | ||
}); | ||
} else { | ||
deferred[ handler ]( newDefer[ action ] ); | ||
} | ||
}); | ||
}).promise(); | ||
}, | ||
// Get a promise for this deferred | ||
// If obj is provided, the promise aspect is added to the object | ||
promise: function( obj ) { | ||
if ( !obj ) { | ||
obj = promise; | ||
} else { | ||
for ( var key in promise ) { | ||
obj[ key ] = promise[ key ]; | ||
} | ||
} | ||
return obj; | ||
} | ||
}, | ||
deferred = promise.promise({}), | ||
key; | ||
for ( key in lists ) { | ||
deferred[ key ] = lists[ key ].fire; | ||
deferred[ key + "With" ] = lists[ key ].fireWith; | ||
} | ||
// Handle state | ||
deferred.done( function() { | ||
state = "resolved"; | ||
}, failList.disable, progressList.lock ).fail( function() { | ||
state = "rejected"; | ||
}, doneList.disable, progressList.lock ); | ||
// Call given func if any | ||
if ( func ) { | ||
func.call( deferred, deferred ); | ||
} | ||
// All done! | ||
return deferred; | ||
}; | ||
// Deferred helper | ||
var when = function( firstParam ) { | ||
var args = sliceDeferred.call( arguments, 0 ), | ||
i = 0, | ||
length = args.length, | ||
pValues = new Array( length ), | ||
count = length, | ||
pCount = length, | ||
deferred = length <= 1 && firstParam && isFunction( firstParam.promise ) ? | ||
firstParam : | ||
Deferred(), | ||
promise = deferred.promise(); | ||
function resolveFunc( i ) { | ||
return function( value ) { | ||
args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; | ||
if ( !( --count ) ) { | ||
deferred.resolveWith( deferred, args ); | ||
} | ||
}; | ||
} | ||
function progressFunc( i ) { | ||
return function( value ) { | ||
pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; | ||
deferred.notifyWith( promise, pValues ); | ||
}; | ||
} | ||
if ( length > 1 ) { | ||
for ( ; i < length; i++ ) { | ||
if ( args[ i ] && args[ i ].promise && isFunction( args[ i ].promise ) ) { | ||
args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) ); | ||
} else { | ||
--count; | ||
} | ||
} | ||
if ( !count ) { | ||
deferred.resolveWith( deferred, args ); | ||
} | ||
} else if ( deferred !== firstParam ) { | ||
deferred.resolveWith( deferred, length ? [ firstParam ] : [] ); | ||
} | ||
return promise; | ||
}; | ||
Deferred.when = when; | ||
Deferred.Callbacks = Callbacks; | ||
return Deferred; | ||
@@ -161,0 +380,0 @@ }); // define for AMD if available |
{ | ||
"name" : "Deferred", | ||
"version" : "0.0.4", | ||
"version" : "0.1.0", | ||
"description" : "A port of the jQuery Deferred library to node js.", | ||
@@ -28,2 +28,7 @@ "keywords" : [ | ||
"url" : "https://github.com/bloveridge" | ||
}, | ||
{ | ||
"name" : "Richard Bateman", | ||
"email" : "taxilian@gmail.com", | ||
"url" : "https://github.com/taxilian" | ||
} | ||
@@ -30,0 +35,0 @@ ], |
jQuery Deferred Library for Node js. | ||
=========== | ||
[website](http://webspinner.github.com/Deferred) | ||
jQuery Deferred solves the following problems: | ||
* support common deferred interface in node | ||
* give some access to the deferred library underpinning in the browser | ||
Usage : | ||
@@ -20,2 +26,34 @@ | ||
}, 1500 ); | ||
``` | ||
``` | ||
Slightly more meaningful Usage Case : | ||
```javascript | ||
var fs = require('fs'); | ||
function readFile(fileName){ | ||
var hasReadFile = new Deferred(); | ||
fs.readFile(fileName, 'utf8',function(err, contents){ | ||
if ( err !== null ) { | ||
return hasReadFile.reject(err); | ||
} | ||
return hasReadFile.resolve(contents); | ||
}); | ||
return hasReadFile.promise(); | ||
} | ||
function parseFile(fileName, parser){ | ||
// parser implemented elsewhere | ||
readFile(fileName) | ||
.done(parser.parse) | ||
.fail(function(err){ | ||
console.error('readFile :: ', err); | ||
}); | ||
} | ||
``` | ||
**What are Deferreds?** | ||
I am putting together a small list of articles worth reading about the concept of deferreds, futures and promises. In it's simplest form a deferred object is a way to introduce a callback stack to a function. | ||
[ColonelPanic](http://colonelpanic.net/2011/11/jquery-deferred-objects/) |
@@ -32,2 +32,17 @@ var vows = require("vows"), | ||
}, | ||
"when deferred is in rejection state": { | ||
topic : Deferred(), | ||
'the deferred object takes failure callbacks': function(topic){ | ||
assert.ok(topic.fail(function(){ | ||
assert.ok(true); | ||
})); | ||
assert.ok(topic.reject()); | ||
}, | ||
'the deferred object will execute failure callbacks even after being rejected' : function( topic ){ | ||
assert.ok(topic.isRejected); | ||
topic.fail(function(){ | ||
assert.ok(true); | ||
}); | ||
} | ||
}, | ||
"when calling deferred as a constructor": { | ||
@@ -91,2 +106,2 @@ topic : new Deferred(), | ||
} | ||
}).export(module); | ||
}).export(module); |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
22480
5
471
59