Skip to content

Instantly share code, notes, and snippets.

@ZhangSen1
Created August 13, 2014 03:53
Show Gist options
  • Save ZhangSen1/7e0a06dee15e5c0e8f08 to your computer and use it in GitHub Desktop.
Save ZhangSen1/7e0a06dee15e5c0e8f08 to your computer and use it in GitHub Desktop.
JQuery Deferred
~function( window ) {
var objExtend = function( tObj, sObj ) {
for ( var i in sObj ) {
if ( typeof sObj[ i ] !== "object" ) {
tObj[ i ] = sObj[ i ];
} else if ( sObj[ i ].constructor == Array ) {
tObj[ i ] = Object.clone( sObj[ i ] );
} else {
tObj[ i ] = tObj[ i ] || {};
Object.extend( tObj[ i ], sObj[ i ] );
}
}
};
var optionsCache = {};
var createOptions = function( options ) {
var object = optionsCache[ options ] = {},
i,
length;
options = options.split(/\s+/);
for ( i = 0, length = options.length; i < length; i++ ) {
object[ options[ i ] ] = true;
}
return object;
};
var Callbacks = function( options ){
options = typeof options == "string" ? ( optionsCache[ options ] || createOptions( options ) ) : {};
var //是否正在触发
firing,
//记下当前上下文和args,之后每次add都会直接触发
memory,
//是否触发完毕
fired,
//待触发的回调个数
firingLength,
//正在触发的回调index
firingIndex,
//待触发的第一个回调index
firingStart,
//存放回调的list
list = [],
//存放上下文和args
stack = !options.once && [];
var fire = function( data ) {
memory = options.memory && data;
fired = true;
firingIndex = firingStart || 0;
//保证每次调用fire都从0执行
firingStart = 0;
//保证每次调用fire都可获得最新的list.length
firingLength = list.length;
firing = true;
for ( ; list && firingIndex < firingLength; firingIndex++ ) {
if (list[ firingIndex ].apply(data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ){
memory = false;
break;
}
};
firing = false;
if ( list ) {
if ( stack ) {
if ( stack.length ) {
fire( stack.shift() );
}
} else if ( memory ) { // (once memory) 进入此分支, 保证之后 add 的 fn 都只执行一次
list = [];
} else { // (once), (once stopOnFalse), (once stopOnFalse memory)
self.disable();
}
}
}
var self = {
add: function(){
if ( list ) {
var start = list.length;
( function add( args ) {
var i,
length,
type;
for ( i = 0, length = args.length; i < length; i++ ) {
arg = args[ i ];
type = typeof arg;
if ( type === "function" ) {
if ( !options.unique || !self.has( arg ) ) {
list.push( arg );
}
} else if ( arg && arg.length && type !== "string" ) {
//递归添加function
add( arg );
}
};
} )( arguments );
if ( firing ) {
firingLength = list.length;
}else if ( memory ) {
//如果memory模式,改变执行fn的index并立即执行
firingStart = start;
fire( memory );
}
}
return this;
},
remove: function() {
if ( list ) {
for (var m = 0; m < arguments.length; m++) {
var arg = arguments[m], index;
};
}
return this;
},
has: function( fn ) {
if ( fn ) {
for ( var n = 0, tmpFn; ( tmpFn = list[ n ] ) != null; n++ ) {
if ( tmpFn == fn ) {
return true;
}
};
return false;
} else {
return !!( list && list.length );
}
},
empty: function(){
list = [];
firingLength = 0;
return this;
},
disable: function() {
list = stack = memory = undefined;
return this;
},
disabled: function() {
return !list;
},
lock: function() {
stack = undefined;
if ( !memory ) {
self.disable();
}
return this;
},
locked: function() {
return !stack;
},
fireWith: function( context, args ) {
if ( list && ( !fired || stack ) ) {
args = args || [];
args = [ context, args.slice ? args.slice() : args ];
//正在执行fn的时候,将 context 和 args 保存
if ( firing ) {
stack.push( args );
}else {
fire( args );
}
}
return this;
},
fire: function() {
self.fireWith( this, arguments );
},
fired: function() {
return !!fired; //!!undefined
}
};
return self;
};
var Deferred = function( func ) {
var tuples = [
//触发回调, 添加回调, 回调列表, 完成状态
[ "resolve", "done", Callbacks("once memory"), "resolved" ],
[ "reject", "fail", Callbacks("once memory"), "rejected"],
[ "notify", "progress", Callbacks("memory")]
],
state = "pending",
//通过对外暴露promise防止更改deferred的状态
promise = {
state: function() {
return state;
},
always: function() {
deferred.done( arguments ).fail( arguments );
return this;
},
then: function() {
},
promise: function( obj ){
return obj != null ? objExtend(deferred, promise) : promise;
}
},
deferred = {};
for ( var i = 0; i < tuples.length; i++ ) {
var tuple = tuples[ i ];
//callbacks
var list = tuple[ 2 ],
//resolved, rejected, undefined
stateString = tuple[ 3 ];
//promise[ done | fail | progress ] = list.add
//实际上就是 Callbacks.add
promise[ tuple[1] ] = list.add;
//初始状态
if ( stateString ) {
//添加3个fn, changeState, callbacks.disable, callbacks.lock
list.add(function() {
state = stateString;
}, tuples[ i ^ 1 ][2].disable, tuples[ 2 ][ 2 ].lock ); //(i ^ 1) index改变,给resolve添加faillist.disable, 给reject添加donelist.disable
}
( function( tmpTuple ) {
// deferred[ resolve | reject | notify ]
deferred[ tmpTuple ] = function() {
//deferred[ resolveWith | rejectWith | notifyWith ] => callbacks.fireWith => callbacks.fire
deferred[ tmpTuple + "With" ]( this === deferred ? promise : this, arguments );
return this;
};
deferred[ tmpTuple + "With" ] = list.fireWith;
} )( tuple[ 0 ] );
};
promise.promise( deferred );
if ( func ) {
func.call( deferred, deferred );
}
return deferred;
};
window.Callbacks = Callbacks;
window.Deferred = Deferred;
}( window );
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment