jQuery Source Reading (12) - Callbacks Callback Object

Posted by jpadie on Tue, 11 Jun 2019 18:23:54 +0200

Remember jQuery Source Reading (1) At that time, I sorted out the overall architecture of the jQuery library, which is mainly divided into three modules:
Entry module, underlying support module and function module, each module is also related.
The previous blogs analyzed the entry module of the jQuery library, mainly the init method. They also analyzed the tool methods in the underlying support module of jQuery, mainly extending the jQuery static method through the jQuery.extend() method.Among the underlying support modules, there are many other modules besides tool methods, and one of their functions is to enhance the reusability and ease of use of code.Examples include callback object module, asynchronous queue module, delayed object, queue, data cache, browser support module, Sizzle selector module, and so on.This time we will focus on sorting out the callback objects in jQuery.

Source Framework and Use

jQuery.Callbacks = function(flags){
    add = function(){
    }
    fire = function(){
    }
    self = {
        //Some variables are defined
        //Here are the ways to manage functions
        add: function(){
        },
        fire: function(){
        },
        fireWith: function(){
        },
        has: function(){
        },
        fired: function(){
        },
        lock: function(){
        },
        locked: function(){
        }
        //Wait
    }
    return self;
}

As you can see from the above architecture, the jQuery.Callbacks function mainly returns a callback object, which manages the callback function in some ways.What exactly is the method?There are many ways to manage functions, such as add(),fire(),fireWith(),lock(), and so on, mainly by adding functions to the list of arrays and executing them one by one.
As you can see, there are two private functions defined in the Callbacks method. Why do you want to do this?
My understanding is: to reduce memory consumption.Because the Callbacks function ultimately returns a callback object, and there are some methods of managing functions in the callback object, it is also possible to write these methods directly into the callback object, but this means that each callback object will have its own method, but these methods are all of the same name, which results in a waste of memory.Instead, add and fire are defined as two private variables. Regardless of how many times the jQuery.Callbacks method is called, the method in the returned callback object calls back the private method in the Callbacks function and points to the same memory address.

Let's look at the parameters of jQuery.Callbacks:

1. once               //Execute the function only once, not repeatedly
2. memory             //All functions add ed into the list of functions will be executed
3. unique             //Do not allow identical functions in the list
4. stopOnFalse        //For a function that returns false, stop executing the following function after execution

First of all, let's understand the function of these parameters:

function a1(){
    console.log('111');
    return false;
}
function a2(){
    console.log('222');
}

Show four sets of diagrams to show the meaning of the four parameters in Callbacks:

once flag

memory Flag

unique flag

stopOnFalse flag

It is easy to understand the meaning of the four parameters from the above four sets of diagrams, so how exactly do these four parameters affect the source code?I would like to illustrate with the following figure

Source Code Analysis

From the figure above, we should know roughly:
In the add function, the function fn Push is added to the list array, and the uniqueness and memory parameters are judged at the same time. If the uniqueness parameter is true, the same function is not pushed into the array; if memory is true, the fire function is called again after add.

In the fire function, all functions in the array are executed, and the once and stopOnFalse parameters are determined.If the once is true, all functions will be executed only once; if stopOnFalse is true, then functions that return false will not execute on subsequent functions after execution.

Based on the above two ideas to see the source code, it will be better to understand.

add method

add method in callback object:

add: function() {
    if ( list ) {
        var length = list.length;
        //The add method here is private in the Callbacks function
        add( arguments );

        if ( firing ) {
            firingLength = list.length;
        } else if ( memory && memory !== true ) {
            //Judge the memory parameter and adjust the fire function
            firingStart = length;
            fire( memory[ 0 ], memory[ 1 ] );
        }
    }
    return this;
}

Private add method in Callbacks function:

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" ) {
            //If the parameter is an array, call the add method recursively
            add( elem );
        } else if ( type === "function" ) {
            //Determine the unique flag and see if there is a function in the list array
            if ( !flags.unique || !self.has( elem ) ) {
                list.push( elem );
            }
        }
    }
}

fire method

fire function in self object:

fire: function() {
    //The fire method debugges the fireWith method of the self object, passing in not only the current scope but also the parameters in the fire
    self.fireWith( this, arguments );
    return this;
}
fireWith: function( context, args ) {
    if ( stack ) { //The stack is an empty array at first and converting to a Boolean value is also true; once sets the stack to undefined, so repeated fire s do not actually execute
        if ( firing ) {  //The symbol firing has not yet been understood;
            if ( !flags.once ) {  
                stack.push( [ context, args ] );
            }
        } else if ( !( flags.once && memory ) ) {  //First execution or multiple executions without once parameter set
            fire( context, args );
        }
    }
    return this;
}
fire = function( context, args ) {
    args = args || [];
    //If the memory parameter is not set, the memory variable is true;
    memory = !flags.memory || [ context, args ];
    fired = true;
    firing = true;
    firingIndex = firingStart || 0;
    firingStart = 0;
    firingLength = list.length;
    for ( ; list && firingIndex < firingLength; firingIndex++ ) {
        //For each function in the list, if it returns false and the stopOnFalse parameter is true, it jumps out of the loop and no longer executes the following function.
        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();        //This is used to set the stack tag to undefined
        } else {
            list = [];
        }
    }
}

For Callbacks callback module, these two functions are the main ones. Of course, there are also methods like self.has, self.empty, self.lock, self.disable, etc. However, these methods are better understood.Overall, the Callbacks module, if you can take into account all the situations and walk along the source code once, is almost understood for the whole module.

Topics: JQuery