jQuery 源码分析(十一) 队列模块 Queue详解_亦心_前端开发者

队列是常用的数据结构之一,只允许在表的前端(队头)进行删除操作(出队),在表的后端(队尾)进行插入操作(入队)。特点是先进先出,最先插入的元素最先被删除。

jquery内部,队列模块为动画模块提供基础功能,负责存储动画函数、自动出队并执行动画函数,同时还要确保动画函数的顺序执行。

jquery的静态方法含有如下API:

  • $.queue(elem,type,data) ;返回或修改匹配元素关联的队列,返回最新的队列,参数如下:
  • $.queue(elem,type,data) ;返回或修改匹配元素关联的队列,返回最新的队列,参数如下:
  •                   elem   ;DOM元素或JavaScript对象

                    type   ;队列名称,默认是标准动画fx

                    data  ;需要设置的队列函数,可以是空(返回队列)、函数(加入队列)或函数数组(替换队列)

    • $.dequeue(elem,type)   ;用于出队并执行匹配元素关联的函数队列中的下一个元素
  • $.dequeue(elem,type)   ;用于出队并执行匹配元素关联的函数队列中的下一个元素
  •                 elem  ;DOM元素或JavaScript对象

                    type  ;是队列名称,默认为动画队列fx

     writer by:大沙漠 QQ:22969969

    jquery/$ 实例方法(可以通过jquery实例调用的):

    • queue(type,data)        ;返回第一个匹配元素的函数队列,或修改所有匹配的元素关联的函数队列,参数如下:
  • queue(type,data)        ;返回第一个匹配元素的函数队列,或修改所有匹配的元素关联的函数队列,参数如下:
  •                 type  ;队列名称

                    data  ;data是可选的函数或函数数组,参数同$.queue()的第三个参数

    • dequeue(type)       ;出队并执行所有匹配元素关联的函数队列中的下一个函数
    • delay(time,type)          ;延迟函数出队执行。通过调用.queue(type,data)向关联的函数队列中插入一个新的函数,在函数内通过setTimeout()延迟下一个函数的出队时间。
    • clearQueue(type)          ;移除匹配元素关联的函数队列中的所有未被执行的函数,内部代码就一句:return this.queue( type || “fx”, [] );
  • dequeue(type)       ;出队并执行所有匹配元素关联的函数队列中的下一个函数
  • delay(time,type)          ;延迟函数出队执行。通过调用.queue(type,data)向关联的函数队列中插入一个新的函数,在函数内通过setTimeout()延迟下一个函数的出队时间。
  • clearQueue(type)          ;移除匹配元素关联的函数队列中的所有未被执行的函数,内部代码就一句:return this.queue( type || “fx”, [] );
  • 举个栗子:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
        <script src="http://libs.baidu.com/jquery/1.7.1/jquery.min.js"></script>
    </head>
    <body>
        <p>123</p>
        <script>
            function f1(){console.log('f1触发');}    //定义两个测试函数
            function f2(){console.log('f2触发')};
    
            $('p').queue('test',f1);                 //将f1入队,队列名称为test
            $('p').dequeue('test');                //将匹配元素的名称为test的函数列表出队并执行
            $('p').queue(f2);                    //将f2放入p匹配元素的队列中,默认为动画队列,会自动执行。
        </script>    
    </body>
    </html>
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
        <script src="http://libs.baidu.com/jquery/1.7.1/jquery.min.js"></script>
    </head>
    <body>
        <p>123</p>
        <script>
            function f1(){console.log('f1触发');}    //定义两个测试函数
            function f2(){console.log('f2触发')};
    
            $('p').queue('test',f1);                 //将f1入队,队列名称为test
            $('p').dequeue('test');                //将匹配元素的名称为test的函数列表出队并执行
            $('p').queue(f2);                    //将f2放入p匹配元素的队列中,默认为动画队列,会自动执行。
        </script>    
    </body>
    </html>

    <!DOCTYPE html><html lang=”en”><head><meta charset=”UTF-8″><title></title><script src=”http://libs.baidu.com/jquery/1.7.1/jquery.min.js></script></head><body><p></p><script>function f1(){console.log(f1触发);}    //定义两个测试函数function f2(){console.log(f2触发)};

    $(p).queue(test,f1);   //将f1入队,队列名称为test $(p).dequeue(test);     //将匹配元素的名称为test的函数列表出队并执行 $(p).queue(f2);         //将f2放入p匹配元素的队列中,默认为动画队列,会自动执行。</script></body></html>

    输出如下:

     

    源码分析

    源码分析源码分析


    jQuery的队列是基于数据缓存模块$.data来实现的,当调用$.queue()时回把函数列表以队列名+’queue’为属性,保存在对应的DOM元素的内部缓存对象上,例如:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
        <script src="http://libs.baidu.com/jquery/1.7.1/jquery.min.js"></script>
    </head>
    <body>
        <p>123</p>
        <script>
            function f1(){console.log('f1触发');}
            $('p').queue('test',f1);    
        </script>    
    </body>
    </html>
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
        <script src="http://libs.baidu.com/jquery/1.7.1/jquery.min.js"></script>
    </head>
    <body>
        <p>123</p>
        <script>
            function f1(){console.log('f1触发');}
            $('p').queue('test',f1);    
        </script>    
    </body>
    </html>

    <!DOCTYPE html><html lang=”en”><head><meta charset=”UTF-8″><title></title><script src=”http://libs.baidu.com/jquery/1.7.1/jquery.min.js”></script></head><body><p></p><script>function f1(){console.log(f1触发);}
    $(
    p).queue(test,f1);
    </script></body></html>

    我们可以在控制台里直接从$.cache里获取对应的属性,如下:

     document.getElementsByTagName(‘p’)[0][$.expando]就是例子里p元素节点对象的$.expando属性,该属性的值会作为$.cache的某个属性,存储着对应这个p元素的数据缓存对象(这是数据缓存模块的内容)

    $.queue和$.dequeue的实现如下:

    jQuery.extend({
        /**/
        queue: function( elem, type, data ) {            //返回或修改匹配元素关联的队列。elem是DOM元素或JavaScript对象,type是队列名称,data是可选的函数或函数数组
            var q;
            if ( elem ) {
                type = ( type || "fx" ) + "queue";                //修正参数type,默认为动画队列fx,在参数type后面加上queue表示这是一个队列
                q = jQuery._data( elem, type );                    //取出参数type对应的队列 如果之前有数据则返回该数组 否则 q等于undefined
    
                // Speed up dequeue by getting out quickly if this is just a lookup
                if ( data ) {                                    //如果传入了data参数
                    if ( !q || jQuery.isArray(data) ) {                //如果type队列不存在,或者type队列存在且data是一个数组
                        q = jQuery._data( elem, type, jQuery.makeArray(data) );    //调用jQuery.makeArray把参数data转换为数组并替换队列
                    } else {
                        q.push( data );                                //队列存在且data不是一个数组则调用数组push方法把参数data放入队列
                    }
                }
                return q || [];
            }
        },
    
        dequeue: function( elem, type ) {                //用于出队并执行匹配元素关联的函数队列中的下一个元素
            type = type || "fx";                            //修正参数type,默认是"fx";
    
            var queue = jQuery.queue( elem, type ),            //获取elem元素的type队列
                fn = queue.shift(),                            //调用shift方法取出队列第一个函数
                hooks = {};                                    //存放出队的函数在执行时的数据
    
            // If the fx queue is dequeued, always remove the progress sentinel
            if ( fn === "inprogress" ) {                    //如果出队的是占位符"inprogress",则丢弃再从队列头部出一个,只有动画队列会设置占位符"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" );                //则在队列开头添加一个占位符"inprogress",表示动画函数正在执行当中
                }
    
                jQuery._data( elem, type + ".run", hooks );    //设置内部数据type+".run",表示参数type对应的队列正在执行,值是hooks,它会被作为第二个参数传递给出队的函数
                fn.call( elem, function() {
                    jQuery.dequeue( elem, type );
                }, hooks );                                    //调用函数方法call执行出队的函数,elem是函数执行的上下文,即关键词this指向的对象;第二个参数是封装了jQuery.dequeue( elem, type )的函数,不会自动执行,需要在出队的函数返回前手动调用next()
            }
    
            if ( !queue.length ) {                            //如果参数type对应的队列在出队后成为空队列,即所有函数都已经出队并执行
                jQuery.removeData( elem, type + "queue " + type + ".run", true );        //调用jQuery.removeData()方法移除参数type对应的数据缓存对象
                handleQueueMarkDefer( elem, type, "queue" );                            //检查匹配元素关联的队列(type+"queue")和计数器(type+"mark")是否完成,如果完成则触发方法.promise()中的计数器
            }
        }
    });
    jQuery.extend({
        /**/
        queue: function( elem, type, data ) {            //返回或修改匹配元素关联的队列。elem是DOM元素或JavaScript对象,type是队列名称,data是可选的函数或函数数组
            var q;
            if ( elem ) {
                type = ( type || "fx" ) + "queue";                //修正参数type,默认为动画队列fx,在参数type后面加上queue表示这是一个队列
                q = jQuery._data( elem, type );                    //取出参数type对应的队列 如果之前有数据则返回该数组 否则 q等于undefined
    
                // Speed up dequeue by getting out quickly if this is just a lookup
                if ( data ) {                                    //如果传入了data参数
                    if ( !q || jQuery.isArray(data) ) {                //如果type队列不存在,或者type队列存在且data是一个数组
                        q = jQuery._data( elem, type, jQuery.makeArray(data) );    //调用jQuery.makeArray把参数data转换为数组并替换队列
                    } else {
                        q.push( data );                                //队列存在且data不是一个数组则调用数组push方法把参数data放入队列
                    }
                }
                return q || [];
            }
        },
    
        dequeue: function( elem, type ) {                //用于出队并执行匹配元素关联的函数队列中的下一个元素
            type = type || "fx";                            //修正参数type,默认是"fx";
    
            var queue = jQuery.queue( elem, type ),            //获取elem元素的type队列
                fn = queue.shift(),                            //调用shift方法取出队列第一个函数
                hooks = {};                                    //存放出队的函数在执行时的数据
    
            // If the fx queue is dequeued, always remove the progress sentinel
            if ( fn === "inprogress" ) {                    //如果出队的是占位符"inprogress",则丢弃再从队列头部出一个,只有动画队列会设置占位符"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" );                //则在队列开头添加一个占位符"inprogress",表示动画函数正在执行当中
                }
    
                jQuery._data( elem, type + ".run", hooks );    //设置内部数据type+".run",表示参数type对应的队列正在执行,值是hooks,它会被作为第二个参数传递给出队的函数
                fn.call( elem, function() {
                    jQuery.dequeue( elem, type );
                }, hooks );                                    //调用函数方法call执行出队的函数,elem是函数执行的上下文,即关键词this指向的对象;第二个参数是封装了jQuery.dequeue( elem, type )的函数,不会自动执行,需要在出队的函数返回前手动调用next()
            }
    
            if ( !queue.length ) {                            //如果参数type对应的队列在出队后成为空队列,即所有函数都已经出队并执行
                jQuery.removeData( elem, type + "queue " + type + ".run", true );        //调用jQuery.removeData()方法移除参数type对应的数据缓存对象
                handleQueueMarkDefer( elem, type, "queue" );                            //检查匹配元素关联的队列(type+"queue")和计数器(type+"mark")是否完成,如果完成则触发方法.promise()中的计数器
            }
        }
    });

    jQuery.extend({
    /**/
    queue:
    function//返回或修改匹配元素关联的队列。elem是DOM元素或JavaScript对象,type是队列名称,data是可选的函数或函数数组var q;
    if ( elem ) {
    type
    //修正参数type,默认为动画队列fx,在参数type后面加上queue表示这是一个队列//取出参数type对应的队列 如果之前有数据则返回该数组 否则 q等于undefined// Speed up dequeue by getting out quickly if this is just a lookupif//如果传入了data参数if//如果type队列不存在,或者type队列存在且data是一个数组//调用jQuery.makeArray把参数data转换为数组并替换队列else {
    q.push( data );
    //队列存在且data不是一个数组则调用数组push方法把参数data放入队列 }
    }
    return [];
    }
    },

    dequeue: function//用于出队并执行匹配元素关联的函数队列中的下一个元素//修正参数type,默认是”fx”;var//获取elem元素的type队列//调用shift方法取出队列第一个函数//存放出队的函数在执行时的数据// If the fx queue is dequeued, always remove the progress sentinelif//如果出队的是占位符”inprogress”,则丢弃再从队列头部出一个,只有动画队列会设置占位符”inprogress” queue.shift();
    }

    if ( fn ) {
    // Add a progress sentinel to prevent the fx queue from being// automatically dequeuedif//如果是动画队列//则在队列开头添加一个占位符”inprogress”,表示动画函数正在执行当中 }

    jQuery._data( elem, type //设置内部数据type+”.run”,表示参数type对应的队列正在执行,值是hooks,它会被作为第二个参数传递给出队的函数function() {
    jQuery.dequeue( elem, type );
    }, hooks );
    //调用函数方法call执行出队的函数,elem是函数执行的上下文,即关键词this指向的对象;第二个参数是封装了jQuery.dequeue( elem, type )的函数,不会自动执行,需要在出队的函数返回前手动调用next() }

    if//如果参数type对应的队列在出队后成为空队列,即所有函数都已经出队并执行true//调用jQuery.removeData()方法移除参数type对应的数据缓存对象//检查匹配元素关联的队列(type+”queue”)和计数器(type+”mark”)是否完成,如果完成则触发方法.promise()中的计数器 }
    }
    });

    type默认等于fx,jQuery的动画效果也是基于Queue实现的,这个fx默认就是动画效果,对于jQuery/$ 实例方法来说,它是调用jQuery的静态方法来实现的,如下:

    type默认等于fx,jQuery的动画效果也是基于Queue实现的,这个fx默认就是动画效果

    jQuery.fn.extend({
        queue: function( type, data ) {            //返回第一个匹配元素的函数队列,或修改所有匹配的元素关联的函数队列。type是队列名称,默认是fx。data参数等同于jQuery.queue中的data参数
            if ( typeof type !== "string" ) {        //修正参数    当传入的格式是queue()或queue(data) (注:data可以是函数或函数数组)时
                data = type;
                type = "fx";
            }
    
            if ( data === undefined ) {                //如果没有传入data参数,
                return jQuery.queue( this[0], type );    //则调用jQuery.queue()返回第一个匹配元素上参数type对应的队列
            }
            return this.each(function() {            //如果传入了data参数
                var queue = jQuery.queue( this, type, data );        //为每一个匹配元素调用jQuery.queue( this, type, data ),把参数(函数)入队,或者用参数data(函数数组)替换队列。
    
                if ( type === "fx" && queue[0] !== "inprogress" ) {    //对于动画队列fx,且没有动画函数正在执行,则立即出队并执行动画函数。
                    jQuery.dequeue( this, type );
                }
            });
        },
        dequeue: function( type ) {                    //出队并执行匹配元素关联的函数队列中的下一个函数
            return this.each(function() {
                jQuery.dequeue( this, type );
            });
        },
        /**/
    })
    jQuery.fn.extend({
        queue: function( type, data ) {            //返回第一个匹配元素的函数队列,或修改所有匹配的元素关联的函数队列。type是队列名称,默认是fx。data参数等同于jQuery.queue中的data参数
            if ( typeof type !== "string" ) {        //修正参数    当传入的格式是queue()或queue(data) (注:data可以是函数或函数数组)时
                data = type;
                type = "fx";
            }
    
            if ( data === undefined ) {                //如果没有传入data参数,
                return jQuery.queue( this[0], type );    //则调用jQuery.queue()返回第一个匹配元素上参数type对应的队列
            }
            return this.each(function() {            //如果传入了data参数
                var queue = jQuery.queue( this, type, data );        //为每一个匹配元素调用jQuery.queue( this, type, data ),把参数(函数)入队,或者用参数data(函数数组)替换队列。
    
                if ( type === "fx" && queue[0] !== "inprogress" ) {    //对于动画队列fx,且没有动画函数正在执行,则立即出队并执行动画函数。
                    jQuery.dequeue( this, type );
                }
            });
        },
        dequeue: function( type ) {                    //出队并执行匹配元素关联的函数队列中的下一个函数
            return this.each(function() {
                jQuery.dequeue( this, type );
            });
        },
        /**/
    })

    jQuery.fn.extend({
    queue:
    function//返回第一个匹配元素的函数队列,或修改所有匹配的元素关联的函数队列。type是队列名称,默认是fx。data参数等同于jQuery.queue中的data参数iftypeof//修正参数 当传入的格式是queue()或queue(data) (注:data可以是函数或函数数组)时 type;
    type
    ;
    }

    if//如果没有传入data参数,returnthis//则调用jQuery.queue()返回第一个匹配元素上参数type对应的队列 }
    returnthisfunction//如果传入了data参数varthis//为每一个匹配元素调用jQuery.queue( this, type, data ),把参数(函数)入队,或者用参数data(函数数组)替换队列。if//对于动画队列fx,且没有动画函数正在执行,则立即出队并执行动画函数。this, type );
    }
    });
    },
    dequeue:
    function//出队并执行匹配元素关联的函数队列中的下一个函数returnthisfunction() {
    jQuery.dequeue(
    this, type );
    });
    },
    /**/
    })

     

    » 本文来自:前端开发者 » 《jQuery 源码分析(十一) 队列模块 Queue详解_亦心_前端开发者》
    » 本文链接地址:https://www.rokub.com/73685.html
    » 您也可以订阅本站:https://www.rokub.com
    赞(0)
    64K

    评论 抢沙发

    评论前必须登录!