• jquery 1.7.2源码解析(四) 异步队列Deferred Object


    异步队列Deferred Object

    一)jQuery.Callbacks( flags )

    1.总体结构

     该函数返回一个链式工具对象(回调函数列表),用于管理一组回调函数。

     

    2.源码分析

    1.工具函数createFlags(flags)

    该函数用于将字符串标记转换为对象格式标记,并把转换结果缓存起来。

    // String to Object flags format cache
    var flagsCache = {};
    
    // Convert String-formatted flags into Object-formatted ones and store in cache
    function createFlags( flags ) {
        var object = flagsCache[ flags ] = {},
            i, length;
        flags = flags.split( /s+/ );
        for ( i = 0, length = flags.length; i < length; i++ ) {
            object[ flags[i] ] = true;
        }
        return object;
    }

     2.工具函数add( args )

    jQuery.Callbacks = function( flags ) {
        // Convert flags from String-formatted to Object-formatted
        // (we check in cache first)
        flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {};
        var // Actual callback list
            list = [],
            // Add one or several callbacks to the list
            add = function( args ) {
                var i,
                    length,
                    elem,
                    type,
                    actual;
                for ( i = 0, length = args.length; i < length; i++ ) {
                    elem = args[ i ];
                    type = jQuery.type( elem );
                    if ( type === "array" ) {
                        // Inspect recursively
                        add( elem );
                    } else if ( type === "function" ) {
                        // Add if not in unique mode and callback is not in
                        if ( !flags.unique || !self.has( elem ) ) {
                            list.push( elem );
                        }
                    }
                }
            },

    3.工具函数fire( context, args )

    使用指定的上下文context和参数args调用数组list中的回调函数

    jQuery.Callbacks = function( flags ) {
        var // Actual callback list
            list = [],
            // Stack of fire calls for repeatable lists
            stack = [],
            // Last fire value (for non-forgettable lists)
            //memory为undefined表示当前回调函数列表没有被触发过
            memory,
            // Flag to know if list was already fired
            fired,
            // Flag to know if list is currently firing
            firing,
            // First callback to fire (used internally by add and fireWith)
            firingStart,
            // End of the loop when firing
            firingLength,
            // Index of currently firing callback (modified by remove if needed)
            firingIndex,
            // Fire callbacks
            fire = function( context, args ) {
                args = args || [];
                //如果当前不是memory模式则设置memory为true,
                // 间接地表示当前回调函数列表已经被触发过
                //如果是memory模式,则memory被赋值为[context, args],表示当前回调函数列表被触发过
                memory = !flags.memory || [ context, args ];
                fired = true;
                //变量firing表示回调函数列表是否正在执行
                firing = true;
                firingIndex = firingStart || 0;
                firingStart = 0;
                firingLength = list.length;
                for ( ; list && firingIndex < firingLength; firingIndex++ ) {
                    if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) {
                        memory = true; // Mark as halted
                        break;
                    }
                }
                firing = false;
                if ( list ) {
                    if ( !flags.once ) {
                        if ( stack && stack.length ) {
                            memory = stack.shift();
                            self.fireWith( memory[ 0 ], memory[ 1 ] );
                        }
                    } else if ( memory === true ) {
                        self.disable();
                    } else {
                        list = [];
                    }
                }
            },
            // Actual Callbacks object
            self = {
                // Have the list do nothing anymore
                disable: function() {
                    list = stack = memory = undefined;
                    return this;
                },
                // Is it disabled?
                disabled: function() {
                    return !list;
                },

    4.callbacks.add()

    添加回调函数到列表中,通过工具函数add(args)实现。

    在memory模式下,并且回调函数列表未在执行中,并且已经被触发过,则立即执行回调函数。

    // Add a callback or a collection of callbacks to the list
                add: function() {
                    if ( list ) {
                        var length = list.length;
                        add( arguments );
                        // Do we need to add the callbacks to the
                        // current firing batch?
                        if ( firing ) {
                            firingLength = list.length;
                        // With memory, if we're not firing then
                        // we should call right away, unless previous
                        // firing was halted (stopOnFalse)
                        } else if ( memory && memory !== true ) {
                            firingStart = length;
                            fire( memory[ 0 ], memory[ 1 ] );
                        }
                    }
                    return this;
                },

    5.callbacks.remove()

    从回调函数列表中移除一个或者一组回调函数,移除前修正firingLength和firingIndex

    remove: function() {
        if ( list ) {
            var args = arguments,
                argIndex = 0,
                argLength = args.length;
            for ( ; argIndex < argLength ; argIndex++ ) {
                for ( var i = 0; i < list.length; i++ ) {
                    if ( args[ argIndex ] === list[ i ] ) {
                        // Handle firingIndex and firingLength
                        if ( firing ) {
                            if ( i <= firingLength ) {
                                firingLength--;
                                if ( i <= firingIndex ) {
                                    firingIndex--;
                                }
                            }
                        }
                        // Remove the element
                        list.splice( i--, 1 );
                        // If we have some unicity property then
                        // we only need to do this once
                        if ( flags.unique ) {
                            break;
                        }
                    }
                }
            }
        }
        return this;
    },

    6. callbacks.disable() 和 callbacks.disabled()

    1)callbacks.disable():禁用回调函数列表

    2)callbacks.disabled():判断函数列表是否被禁用

    // Have the list do nothing anymore
                disable: function() {
                    list = stack = memory = undefined;
                    return this;
                },
     // Is it disabled?
                disabled: function() {
                    return !list;
                },

    禁用后无法添加、移除、触发回调函数,并会立即停止正在执行的回调函数。

    7.锁定 callbacks.lock()、 callbacks.locked()

    // Lock the list in its current state
    lock: function() {
        //这会导致无法再次触发回调函数
        stack = undefined;
        if ( !memory || memory === true ) {
            self.disable();
        }
        return this;
    },
    // Is it locked?
    locked: function() {
        return !stack;
    },

    二)jQuery.Deferred(func)

    该方法返回一个链式工具对象,我们把该链式工具对象称为"异步队列"。

    异步队列的三种状态:

    1)待定(pending):初始时处于的状态

    2)成功(resolved):调用方法deferred.resolved(args)或resolvedWith(context, args)

    将改变异步队列为成功状态,并且立即执行添加的所有"成功回调函数"。

    3)失败(rejected):调用方法deferred.reject(args)和方法deferred.rejectWith(context, args)

    则改变状态为失败状态,并立即执行所有"失败回调函数"。

    一旦异步队列进入成功或者失败状态,就会保持它的状态不变。再次调用以上方法就会被忽略。

    异步队列内部维护了三个函数列表:成功回调函数列表、失败回调函数列表、消息回调函数列表。

    //可选参数func
    Deferred: function( func ) {
        var doneList = jQuery.Callbacks( "once memory" ),
            failList = jQuery.Callbacks( "once memory" ),
            progressList = jQuery.Callbacks( "memory" ),
            //设置初始状态
            state = "pending",
            lists = {
                resolve: doneList,
                reject: failList,
                notify: progressList
            },
            //创建异步队列的只读副本
            promise = {
                done: doneList.add,
                fail: failList.add,
                progress: progressList.add,
    
                state: function() {
                    return state;
                },
    
                // Deprecated
                isResolved: doneList.fired,
                isRejected: failList.fired,
    
                //同时添加成功、失败和消息回调函数
                then: function( doneCallbacks, failCallbacks, progressCallbacks ) {
                    deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks );
                    return this;
                },
                //用于将回调函数同时添加到成功回调函数列表和失败回调函数列表
                always: function() {
                    deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments );
                    return this;
                },
                pipe: function( fnDone, fnFail, fnProgress ) {
                    return jQuery.Deferred(function( newDefer ) {
                        jQuery.each( {
                            done: [ fnDone, "resolve" ],
                            fail: [ fnFail, "reject" ],
                            progress: [ fnProgress, "notify" ]
                        }, function( handler, data ) {
                            var fn = data[ 0 ],
                                action = data[ 1 ],
                                returned;
                            if ( jQuery.isFunction( fn ) ) {
                                deferred[ handler ](function() {
                                    returned = fn.apply( this, arguments );
                                    if ( returned && jQuery.isFunction( returned.promise ) ) {
                                        returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify );
                                    } else {
                                        newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] );
                                    }
                                });
                            } else {
                                deferred[ handler ]( newDefer[ action ] );
                            }
                        });
                    }).promise();
                },
                // Get a promise for this deferred
                // If obj is provided, the promise aspect is added to the object
                promise: function( obj ) {
                    if ( obj == null ) {
                        obj = promise;
                    } else {
                        for ( var key in promise ) {
                            obj[ key ] = promise[ key ];
                        }
                    }
                    return obj;
                }
            },
            deferred = promise.promise({}),
            key;
    
        for ( key in lists ) {
            deferred[ key ] = lists[ key ].fire;
            deferred[ key + "With" ] = lists[ key ].fireWith;
        }
    
        // Handle state
        deferred.done( function() {
            state = "resolved";
        }, failList.disable, progressList.lock ).fail( function() {
            state = "rejected";
        }, doneList.disable, progressList.lock );
    
        // Call given func if any
        if ( func ) {
            func.call( deferred, deferred );
        }
    
        // All done!
        return deferred;
    },

    三)jQuery.when(deferreds)

    该方法提供了基于一个或者多个对象的状态来执行回调函数的功能,

    通常是基于具有异步事件的异步队列。

  • 相关阅读:
    1014. 福尔摩斯的约会
    1009. 说反话
    1002. 写出这个数
    1031. 查验身份证
    1021. 个位数统计
    1006. 换个格式输出整数
    1058. A+B in Hogwarts
    1027. Colors in Mars
    1019. General Palindromic Number
    Windows 新装进阶操作指南
  • 原文地址:https://www.cnblogs.com/Shadowplay/p/9831097.html
Copyright © 2020-2023  润新知