Jump To …

05-queue.js

jQuery Annotated Source.

Home | Previous Chapter | Next Chapter

Queue

function handleQueueMarkDefer( elem, type, src ) {
  var deferDataKey = type + "defer",
    queueDataKey = type + "queue",
    markDataKey = type + "mark",
    defer = jQuery.data( elem, deferDataKey, undefined, true );
  if ( defer &&
    ( src === "queue" || !jQuery.data( elem, queueDataKey, undefined, true ) ) &&
    ( src === "mark" || !jQuery.data( elem, markDataKey, undefined, true ) ) ) {

Give room for hard-coded callbacks to fire first and eventually mark/queue something else on the element

    setTimeout( function() {
      if ( !jQuery.data( elem, queueDataKey, undefined, true ) &&
        !jQuery.data( elem, markDataKey, undefined, true ) ) {
        jQuery.removeData( elem, deferDataKey, true );
        defer.resolve();
      }
    }, 0 );
  }
}

jQuery.extend({

  _mark: function( elem, type ) {
    if ( elem ) {
      type = (type || "fx") + "mark";
      jQuery.data( elem, type, (jQuery.data(elem,type,undefined,true) || 0) + 1, true );
    }
  },

  _unmark: function( force, elem, type ) {
    if ( force !== true ) {
      type = elem;
      elem = force;
      force = false;
    }
    if ( elem ) {
      type = type || "fx";
      var key = type + "mark",
        count = force ? 0 : ( (jQuery.data( elem, key, undefined, true) || 1 ) - 1 );
      if ( count ) {
        jQuery.data( elem, key, count, true );
      } else {
        jQuery.removeData( elem, key, true );
        handleQueueMarkDefer( elem, type, "mark" );
      }
    }
  },

  queue: function( elem, type, data ) {
    if ( elem ) {
      type = (type || "fx") + "queue";
      var q = jQuery.data( elem, type, undefined, true );

Speed up dequeue by getting out quickly if this is just a lookup

      if ( data ) {
        if ( !q || jQuery.isArray(data) ) {
          q = jQuery.data( elem, type, jQuery.makeArray(data), true );
        } else {
          q.push( data );
        }
      }
      return q || [];
    }
  },

  dequeue: function( elem, type ) {
    type = type || "fx";

    var queue = jQuery.queue( elem, type ),
      fn = queue.shift(),
      defer;

If the fx queue is dequeued, always remove the progress sentinel

    if ( fn === "inprogress" ) {
      fn = queue.shift();
    }

    if ( fn ) {

Add a progress sentinel to prevent the fx queue from being automatically dequeued

      if ( type === "fx" ) {
        queue.unshift("inprogress");
      }

      fn.call(elem, function() {
        jQuery.dequeue(elem, type);
      });
    }

    if ( !queue.length ) {
      jQuery.removeData( elem, type + "queue", true );
      handleQueueMarkDefer( elem, type, "queue" );
    }
  }
});

jQuery.fn.extend({
  queue: function( type, data ) {
    if ( typeof type !== "string" ) {
      data = type;
      type = "fx";
    }

    if ( data === undefined ) {
      return jQuery.queue( this[0], type );
    }
    return this.each(function() {
      var queue = jQuery.queue( this, type, data );

      if ( type === "fx" && queue[0] !== "inprogress" ) {
        jQuery.dequeue( this, type );
      }
    });
  },
  dequeue: function( type ) {
    return this.each(function() {
      jQuery.dequeue( this, type );
    });
  },

Based off of the plugin by Clint Helfers, with permission. http://blindsignals.com/index.php/2009/07/jquery-delay/

  delay: function( time, type ) {
    time = jQuery.fx ? jQuery.fx.speeds[time] || time : time;
    type = type || "fx";

    return this.queue( type, function() {
      var elem = this;
      setTimeout(function() {
        jQuery.dequeue( elem, type );
      }, time );
    });
  },
  clearQueue: function( type ) {
    return this.queue( type || "fx", [] );
  },

Get a promise resolved when queues of a certain type are emptied (fx is the type by default)

  promise: function( type, object ) {
    if ( typeof type !== "string" ) {
      object = type;
      type = undefined;
    }
    type = type || "fx";
    var defer = jQuery.Deferred(),
      elements = this,
      i = elements.length,
      count = 1,
      deferDataKey = type + "defer",
      queueDataKey = type + "queue",
      markDataKey = type + "mark",
      tmp;
    function resolve() {
      if ( !( --count ) ) {
        defer.resolveWith( elements, [ elements ] );
      }
    }
    while( i-- ) {
      if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) ||
          ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) ||
            jQuery.data( elements[ i ], markDataKey, undefined, true ) ) &&
          jQuery.data( elements[ i ], deferDataKey, jQuery._Deferred(), true ) )) {
        count++;
        tmp.done( resolve );
      }
    }
    resolve();
    return defer.promise();
  }
});