javascript - Where does jQuery do animations/timers in `$.queue()`? -


i looking through source of jquery (specifically queue() function) , saw in puts function .data() object associated element:

queue: function( elem, type, data ) {     var q;     if ( elem ) {         type = ( type || "fx" ) + "queue";         q = jquery._data( elem, type );          // speed dequeue getting out if lookup         if ( data ) {             if ( !q || jquery.isarray(data) ) {                 q = jquery._data( elem, type, jquery.makearray(data) );             } else {                 q.push( data );             }         }         return q || [];     } } 

now looking @ ._data .data() fourth argument of true, timers or animations being set? or function calls matter:

data: function( elem, name, data, pvt /* internal use */ ) {     if ( !jquery.acceptdata( elem ) ) {         return;     }      var privatecache, thiscache, ret,         internalkey = jquery.expando,         getbyname = typeof name === "string",          // have handle dom nodes , js objects differently because ie6-7         // can't gc object references across dom-js boundary         isnode = elem.nodetype,          // dom nodes need global jquery cache; js object data         // attached directly object gc can occur automatically         cache = isnode ? jquery.cache : elem,          // defining id js objects if cache exists allows         // code shortcut on same path dom node no cache         id = isnode ? elem[ internalkey ] : elem[ internalkey ] && internalkey,         isevents = name === "events";      // avoid doing more work need when trying data on     // object has no data @     if ( (!id || !cache[id] || (!isevents && !pvt && !cache[id].data)) && getbyname && data === undefined ) {         return;     }      if ( !id ) {         // dom nodes need new unique id each element since data         // ends in global cache         if ( isnode ) {             elem[ internalkey ] = id = ++jquery.uuid;         } else {             id = internalkey;         }     }      if ( !cache[ id ] ) {         cache[ id ] = {};          // avoids exposing jquery metadata on plain js objects when object         // serialized using json.stringify         if ( !isnode ) {             cache[ id ].tojson = jquery.noop;         }     }      // object can passed jquery.data instead of key/value pair; gets     // shallow copied on onto existing cache     if ( typeof name === "object" || typeof name === "function" ) {         if ( pvt ) {             cache[ id ] = jquery.extend( cache[ id ], name );         } else {             cache[ id ].data = jquery.extend( cache[ id ].data, name );         }     }      privatecache = thiscache = cache[ id ];      // jquery data() stored in separate object inside object's internal data     // cache in order avoid key collisions between internal data , user-defined     // data.     if ( !pvt ) {         if ( !thiscache.data ) {             thiscache.data = {};         }          thiscache = thiscache.data;     }      if ( data !== undefined ) {         thiscache[ jquery.camelcase( name ) ] = data;     }      // users should not attempt inspect internal events object using jquery.data,     // undocumented , subject change. listen? no.     if ( isevents && !thiscache[ name ] ) {         return privatecache.events;     }      // check both converted-to-camel , non-converted data property names     // if data property specified     if ( getbyname ) {          // first try find as-is property data         ret = thiscache[ name ];          // test null|undefined property data         if ( ret == null ) {              // try find camelcased property             ret = thiscache[ jquery.camelcase( name ) ];         }     } else {         ret = thiscache;     }      return ret; } 

edit zzzzbov:

animate: function( prop, speed, easing, callback ) {     var optall = jquery.speed( speed, easing, callback );      if ( jquery.isemptyobject( prop ) ) {         return this.each( optall.complete, [ false ] ); ....     return optall.queue === false ?         this.each( doanimation ) :         this.queue( optall.queue, doanimation ); 

jquery's animate method complex beast (see reference below). starts normalizing parameters, , jumps doanimation function callback used jquery's queue method. jquery queue's animations happen in order. queue doesn't animate itself, acts trigger code performs animation.

at end of doanimation, there loop animate every relevant property in animation (lines 8576 - 8618, v1.7.2). first inner-line of loop instantiates new jquery.fx object:

e = new jquery.fx( this, opt, p ); 

at end of loop, e.custom(...) called in couple places. important function. if through jquery.fx.prototype.custom (see reference below), you'll find:

if ( t() && jquery.timers.push(t) && !timerid ) {     timerid = setinterval( fx.tick, fx.interval ); } 

the line setinterval jquery's animation heartbeat started. points jquery.fx.tick (see reference below) iterates through every timer in jquery.timers. if @ snippet above, you'll notice part of if statement involves pushing t stack of timers. t set in jquery.fx.prototype.custom as:

function t( gotoend ) {     return self.step( gotoend ); } 

and right there jquery's animation happens.


reference

jquery's animate function (lines 8484 - 8627, v1.7.2):

animate: function( prop, speed, easing, callback ) {     var optall = jquery.speed( speed, easing, callback );      if ( jquery.isemptyobject( prop ) ) {         return this.each( optall.complete, [ false ] );     }      // not change referenced properties per-property easing lost     prop = jquery.extend( {}, prop );      function doanimation() {         // xxx 'this' not have nodename when running         // test suite          if ( optall.queue === false ) {             jquery._mark( );         }          var opt = jquery.extend( {}, optall ),             iselement = this.nodetype === 1,             hidden = iselement && jquery(this).is(":hidden"),             name, val, p, e, hooks, replace,             parts, start, end, unit,             method;          // store per property easing , used determine when animation complete         opt.animatedproperties = {};          // first pass on propertys expand / normalize         ( p in prop ) {             name = jquery.camelcase( p );             if ( p !== name ) {                 prop[ name ] = prop[ p ];                 delete prop[ p ];             }              if ( ( hooks = jquery.csshooks[ name ] ) && "expand" in hooks ) {                 replace = hooks.expand( prop[ name ] );                 delete prop[ name ];                  // not quite $.extend, wont overwrite keys present.                 // - reusing 'p' above because have correct "name"                 ( p in replace ) {                     if ( ! ( p in prop ) ) {                         prop[ p ] = replace[ p ];                     }                 }             }         }          ( name in prop ) {             val = prop[ name ];             // easing resolution: per property > opt.specialeasing > opt.easing > 'swing' (default)             if ( jquery.isarray( val ) ) {                 opt.animatedproperties[ name ] = val[ 1 ];                 val = prop[ name ] = val[ 0 ];             } else {                 opt.animatedproperties[ name ] = opt.specialeasing && opt.specialeasing[ name ] || opt.easing || 'swing';             }              if ( val === "hide" && hidden || val === "show" && !hidden ) {                 return opt.complete.call( );             }              if ( iselement && ( name === "height" || name === "width" ) ) {                 // make sure nothing sneaks out                 // record 3 overflow attributes because ie not                 // change overflow attribute when overflowx ,                 // overflowy set same value                 opt.overflow = [ this.style.overflow, this.style.overflowx, this.style.overflowy ];                  // set display property inline-block height/width                 // animations on inline elements having width/height animated                 if ( jquery.css( this, "display" ) === "inline" &&                         jquery.css( this, "float" ) === "none" ) {                      // inline-level elements accept inline-block;                     // block-level elements need inline layout                     if ( !jquery.support.inlineblockneedslayout || defaultdisplay( this.nodename ) === "inline" ) {                         this.style.display = "inline-block";                      } else {                         this.style.zoom = 1;                     }                 }             }         }          if ( opt.overflow != null ) {             this.style.overflow = "hidden";         }          ( p in prop ) {             e = new jquery.fx( this, opt, p );             val = prop[ p ];              if ( rfxtypes.test( val ) ) {                  // tracks whether show or hide based on private                 // data attached element                 method = jquery._data( this, "toggle" + p ) || ( val === "toggle" ? hidden ? "show" : "hide" : 0 );                 if ( method ) {                     jquery._data( this, "toggle" + p, method === "show" ? "hide" : "show" );                     e[ method ]();                 } else {                     e[ val ]();                 }              } else {                 parts = rfxnum.exec( val );                 start = e.cur();                  if ( parts ) {                     end = parsefloat( parts[2] );                     unit = parts[3] || ( jquery.cssnumber[ p ] ? "" : "px" );                      // need compute starting value                     if ( unit !== "px" ) {                         jquery.style( this, p, (end || 1) + unit);                         start = ( (end || 1) / e.cur() ) * start;                         jquery.style( this, p, start + unit);                     }                      // if +=/-= token provided, we're doing relative animation                     if ( parts[1] ) {                         end = ( (parts[ 1 ] === "-=" ? -1 : 1) * end ) + start;                     }                      e.custom( start, end, unit );                  } else {                     e.custom( start, val, "" );                 }             }         }          // js strict compliance         return true;     }      return optall.queue === false ?         this.each( doanimation ) :         this.queue( optall.queue, doanimation ); } 

instantiation of jquery.fx (line 8577, v1.7.2):

e = new jquery.fx( this, opt, p ); 

jquery.fx.prototype.custom (lines 8806 - 8836, v1.7.2):

// start animation 1 number custom: function( from, to, unit ) {     var self = this,         fx = jquery.fx;      this.starttime = fxnow || createfxnow();     this.end = to;     this.now = this.start = from;     this.pos = this.state = 0;     this.unit = unit || this.unit || ( jquery.cssnumber[ this.prop ] ? "" : "px" );      function t( gotoend ) {         return self.step( gotoend );     }      t.queue = this.options.queue;     t.elem = this.elem;     t.savestate = function() {         if ( jquery._data( self.elem, "fxshow" + self.prop ) === undefined ) {             if ( self.options.hide ) {                 jquery._data( self.elem, "fxshow" + self.prop, self.start );             } else if ( self.options.show ) {                 jquery._data( self.elem, "fxshow" + self.prop, self.end );             }         }     };      if ( t() && jquery.timers.push(t) && !timerid ) {         timerid = setinterval( fx.tick, fx.interval );     } } 

jquery.fx.tick (lines 8949 - 8965, v1.7.2):

tick: function() {     var timer,         timers = jquery.timers,         = 0;      ( ; < timers.length; i++ ) {         timer = timers[ ];         // checks timer has not been removed         if ( !timer() && timers[ ] === timer ) {             timers.splice( i--, 1 );         }     }      if ( !timers.length ) {         jquery.fx.stop();     } } 

Comments

Popular posts from this blog

java - Play! framework 2.0: How to display multiple image? -

gmail - Is there any documentation for read-only access to the Google Contacts API? -

php - Controller/JToolBar not working in Joomla 2.5 -