jQuery 源码 : queue 主要针对animate这个操作


queue	

队列方法:执行顺序的管理。


(1)jQuery用extend扩展,是有工具方法。

jQuery.extend({
	queue  			//	添加	类似数组的push
	dequeue 		// 	删除	类似于 shift
	_queueHooks		//	给传入的数据进行处理,加个 argu+queue。
});


注意:在	queue 和 dequeue	 中存入的必须是一个函数,其他格式不可以。

例子:(1)

工具方法使用。
	function aaa() {
		alert('aaa');
	}

	function bbb() {
		alert('bbb');
	}

	$.queue(document, 'q1', aaa);		// 	这里创建了一个q1的队列。存入了一个值,是个函数aaa
	$.queue(document, 'q1', bbb);		//    这里在去q1队列中加入了第二个值,是函数bbb

	// $.queue(document, 'q1', [aaa, bbb]);		//也可以直接存入一个数组。
	console.log( $.queue(document, 'q1') ); 	// FF 打印出	[aaa(), bbb()]。

// 注意:queue 和 dequeue	 中存入的必须是一个函数。

	$.dequeue(document, 'q1');			//  弹出 aaa函数 ,出队,只是把第一个函数取出来。并执行 aaa();
	$.dequeue(document, 'q1');			//  弹出 bbb函数 ,出队,又把第一项给读取出来。并执行 bbb();
//注意: dequeue,取出第一个变量,并执行它,其他的类型,无法执行。


例子:(2)

实例方法使用。

	$(document).queue('p1', aaa);
	$(document).queue('p1', bbb);
	console.log( $.queue(document, 'p1') ); 		// FF 打印出	[aaa(), bbb()]。
	$(document).dequeue('p1', bbb);			    // 打印 aaa函数。




(2)jQuery.fn.extend 扩展的是实例方法。
jQuery.fn.extend({
	queue
	dequeue	
	delay		// 延迟队列
	clearQueue
	promise
});


	
思考:队列的作用。
	
	$('#test').click(function () {
		$(this).animate({ 400}, 2000);	      // (1)
		$(this).animate({height: 400}, 2000);	      // (2)
		$(this).animate({left: 200}, 2000);		 // (3)这里position要absolute

		//  和上面一样。
		//  $(this).animate({ 400}, 2000).animate({height: 400}, 2000).animate({left: 200}, 2000);
	});

//	这里的执行顺序是一次执行,不是并发执行。(1)-->(2)-->(3)
//	用定时器开启,然后执行。但是定时器是异步操作。setInterval是异步操作。
//	这个就是用队列实现的。

当使用动作函数的时候,用 queue 依次将其中对函数压入队列fx。运行的时候,就 dequeue 操作。
deferred 的是控制一个操作,queue 是控制一系列的操作。
但是 deferred 针对异步操作,延迟对象更强大一些。主要针对的是一个异步操作的控制。
queue是针对多个的。deferred很难完成多异步的操作。
在 jQuery 中 queue 主要针对的是运动的操作,去解决连续运动的这个操作。


例子

A--------------------	使用规则
	$(this).animate({ 400}, 2000).queue('fx', function () {
		$(this).dequeue();		//	如果没有这个出队操作,后面的,就无法继续执行了。
	}).animate({height: 400}, 2000).animate({left: 200}, 2000);
	
B---------------------	fx可以省略,并且如果调用函数,需要使用$(this).dequeue();
//	这里的 fx 是可以省略的,默认就是。
	$(this).animate({ 400}, 2000).queue(function () {
		$(this).dequeue();		//	如果没有这个出队操作,后面的,就无法继续执行了。
	}).animate({height: 400}, 2000).animate({left: 200}, 2000);


C---------------------	传入的参数,等价于dequeue。

	$(this).animate({ 400}, 2000).queue(function (next) {
		$(this).css('left', 200);
		next();
	}).animate({height: 400}, 2000).animate({left: 200}, 2000);

D-------------	利用回调函数的形式

	$(this).animate({ 400}, 2000, function () {
			$(this).css('left', 200);
	}).animate({height: 400}, 2000).animate({left: 200}, 2000);

E--------------------	可以通过控制queue,来控制,保证异步的顺序。
	$(this).animate({ 400}, 2000).queue(function (next) {
			
		var _this = this;
		var timer = setInterval(function () {
			_this.style.height = ( _this.offsetHeight + 1 ) + "px";

			if (_this.offsetHeight >= 400) {
				next();		//	可以控制出队的时间,没有next的执行,就不会执行下一个动作。
				clearInterval(timer);
			}

		}, 30);

	}).animate({left: 200}, 2000);


F--------------------	delay(2000) 延迟2秒钟

$('#test').click(function () {

	$(this).animate({ 400}, 2000).delay(2000).animate({left: 200}, 2000);

});

G---------------------	promise 所有运动执行完成以后,执行 promise 挂载的函数。
$('#test').click(function () {

	$(this).animate({ 400}, 2000).delay(2000).animate({left: 200}, 2000);

	$(this).promise().done(function () {
			alert('done');
		});
	});

});



源码: jQuery.extend({ queue: function( elem, type, data ) { var queue; // 当元素存在的时候 if ( elem ) { // 可以直接写一个type类型,不写默认就是fx type = ( type || "fx" ) + "queue"; queue = data_priv.get( elem, type ); // 如何往队列中存储,得到数组 // Speed up dequeue by getting out quickly if this is just a lookup // 如果存在第三个参数,就是传入的执行函数。 if ( data ) { // 判断 queue 是否存在,如果不存在,就执行,创建一个。 // 或者存入的 data 是数组,就重写,并覆盖以前的所有方法。搞一个新的 队列 queue 。 if ( !queue || jQuery.isArray( data ) ) { // 设定数据。 queue = data_priv.access( elem, type, jQuery.makeArray(data) ); } // 存在,就压入。 else { queue.push( data ); } } // 没有酒返回空数组,写2个参数,就返回集合。 return queue || []; } }, // 出队 dequeue: function( elem, type ) { // 不写就默认fx type = type || "fx"; // 先去得到 queue 的队列。 var queue = jQuery.queue( elem, type ), // queue 初始化。 startLength = queue.length, // 获取数组长度。 // 返回第一项。 fn = queue.shift(), hooks = jQuery._queueHooks( elem, type ), // 出队的操作 next(), 跟 dequeue 一回事。 next = function() { jQuery.dequeue( elem, type ); }; // If the fx queue is dequeued, always remove the progress sentinel // 当定时器结束的时候, 进行出队。 if ( fn === "inprogress" ) { fn = queue.shift(); startLength--; // 长度 - 1 } // 是否是函数。 if ( fn ) { // Add a progress sentinel to prevent the fx queue from being // automatically dequeued // 是默认情况下,就填入。 if ( type === "fx" ) { // inprogress 针对fx。添加 inprogress // 只有三处用了 inprogress。 // inprogress 的作用就是让队列,可以自动的进行出队的操作。 queue.unshift( "inprogress" ); // 只有第一次,添加 } // clear up the last queue stop function delete hooks.stop; // fn 是队列 刚退出来的函数, 传入参数, 进行call执行。 fn.call( elem, next, hooks ); } if ( !startLength && hooks ) { hooks.empty.fire(); } }, // not intended for public consumption - generates a queueHooks object, or returns the current one // 私有的函数,清理一下缓存。 // _queueHooks 的目的就是,将fx(默认),或者用户传入的的队列名,---->> 这些都是缓存到data中了, // 当全部结束的时候,将那些 fixqueue, 等,对咧名称,全部干掉。 _queueHooks: function( elem, type ) { var key = type + "queueHooks"; // data_priv.get( elem, key ) 取缓存,没有酒添加一个。 // return data_priv.get( elem, key ) || data_priv.access( elem, key, { empty: jQuery.Callbacks("once memory").add(function() { data_priv.remove( elem, [ type + "queue", key ] ); }) }); } }); 实例的源码 jQuery.fn.extend({ queue: function( type, data ) { var setter = 2; 判断是否是字符串。如果不是字符串,那么可能传入的是函数,或者数组。 if ( typeof type !== "string" ) { data = type; type = "fx"; setter--; } // 查看的状态 // 传入的参数小于2. if ( arguments.length < setter ) { return jQuery.queue( this[0], type ); // 返回一组元素的第一项。 } // 若果是空的话,就返回this对象,如果不是空,就要遍历了。 return data === undefined ? this : this.each(function() { var queue = jQuery.queue( this, type, data ); // ensure a hooks for this queue               //这里:_queueHooks了以后,看这个是不是空的,如果不是,就填入一个数据。 jQuery._queueHooks( this, type ); // 队列第0项,不是 inprogress 就出队,只是针对第一次出队操作,后续就不会了。 //    针对animate运动的。$(document).queue('p1', aaa).$(document).queue('p1', bbb); // 如果连续多个操作,第一个就直接执行了,然后第二个进入队列。
          // inprogress干的就是这个。保证执行第一个,后面的进行入队操作,等待前面的结束,激活后面的。 //    这里,$(document).queue('p1', aaa) 执行完,就要出队,然后再执行后面的动作。 // 这是一个入队方法,但是为什么调用出队呢? //    针对的就是这个 $(document).queue('p1', aaa) 第一个要直接运动起来。后面的压入队列,等待第一个执行结束,在进行后面的. // 逻辑比较简单
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. // // 延迟时间的。time == 600 delay: function( time, type ) { time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; type = type || "fx"; return this.queue( type, function( next, hooks ) { // 这里搞了一个定时器,让你 time 时间以后,再进行出队操作。 var timeout = setTimeout( next, time ); hooks.stop = function() { clearTimeout( timeout ); }; }); }, // 清空 clearQueue: function( type ) { return this.queue( type || "fx", [] ); }, // 这里和 Deferred 和 callbacks 里面的东西差不多。 // 就是等到运动结束了,执行个函数什么的, 让promise去执行就好了。 // Get a promise resolved when queues of a certain type // are emptied (fx is the type by default) promise: function( type, obj ) { var tmp, // 计数 count = 1, // Deferred 的对象 defer = jQuery.Deferred(), elements = this, i = this.length, // 累加多少,就减多少。 resolve = function() { // 直到 count == 0 的时候,才会执行这个 resolveWith--》》就是完成了---》》然后就是done。 // 这里就不存在fail了。 if ( !( --count ) ) { defer.resolveWith( elements, [ elements ] ); } }; if ( typeof type !== "string" ) { obj = type; type = undefined; } type = type || "fx"; while( i-- ) { tmp = data_priv.get( elements[ i ], type + "queueHooks" ); if ( tmp && tmp.empty ) { //这个队列存在的时候,就进行累加。 count++; tmp.empty.add( resolve ); // 添加事件 } } resolve(); // 内部函数调用, return defer.promise( obj ); } });
原文地址:https://www.cnblogs.com/hgonlywj/p/4868710.html