Reprint Aaron Blog----jQuery 2.0.3 Source Analysis callback Object-callbacks

Source: Internet
Author: User

SOURCE api:http://api.jquery.com/jquery.callbacks/

Jquery.callbacks () was newly added in version 1.7. It is a multipurpose callback function list object that provides a powerful way to manage callback function queues.

So where is the jquery.callbacks use scene?

In many cases it is necessary to control a sequence of function executions. Then generally a queue function is required to handle this problem

Let's look at some code.

function Aaron (List, callback) {    setTimeout (function () {      var task = List.shift ();      Task (); Execute function      if (task.length > 0) {  //recursive decomposition        setTimeout (Arguments.callee, +)      } else {        callback () }}    ()  }  Aaron ([function () {    alert (' a ')  },function () {    alert (' B ')  }], function () {    alert (' Callback ')  })
Pop ' a ', ' B ', ' Callback ', respectively

Passing in a set of function parameters, by recursive parsing, sub-execution, in fact, by settimeout can add the function to the end of the queue to execute the principle

But isn't it a lot of trouble to write like this? *****

We'll change the way jquery offers it.

var callbacks = $. Callbacks ();  Callbacks.add (function () {    alert (' a ');  })  Callbacks.add (function () {    alert (' B ');  })  Callbacks.fire (); Output result: ' A ' B '

is not a lot more convenient, the code is very clear, so it is a multipurpose callback function list object, provides a powerful way to manage the callback function queue.

Several convenient processing parameters are also available.

    • once: Make sure that this callback list only executes (. Fire ()) once (like a deferred Deferred).
    • memory: Keep the previous value, add the latest value to the back of this list and immediately execute any callback (like a deferred Deferred).
    • unique: Make sure that only one callback is added at a time (so there are no duplicate callbacks in the list).
    • stopOnFalse: Interrupts call when a callback returns false
var callbacks = $. Callbacks (' once ');  Callbacks.add (function () {    alert (' a ');  })  Callbacks.add (function () {    alert (' B ');  })  Callbacks.fire (); Output: ' A ' B '  callbacks.fire ();//Not executed

The once function is to make the callback queue perform only once

OK, we probably know what this is for, and we can start cooking.

.CALLBACKSIsInJQUERY inside Department Make with , such as . ajax,$. Deferred and other components provide the basic functions of the function, jquery introduced the deferred object (asynchronous queue) in 1.5, jquery inside all of the basic asynchronous code is translated into synchronous code promise to execute, later in the discussion

According to the API of Jquery.callbacks ()

Here are a few ways to do this:

        adds a collection of callbacks or callbacks to the Callbacks.add () callback list. Callbacks.disable ()    disables callback callbacks.disabled () in the callback list to   determine whether the callback list is disabled. Callbacks.empty ()      removes all callbacks from the list. Callbacks.fire ()       calls all callbacks callbacks.fired () with the given parameters to      access all callbacks in the given context and argument list. Callbacks.firewith ()   accesses all callbacks in the given context and argument list. Callbacks.has ()        determines whether a callback list is provided in the list that callbacks.lock ()       locks the current state. Callbacks.locked ()     determines whether the callback list is locked. Callbacks.remove ()     removes a callback or callback collection from the callback list.

Our Crossing Network offers demo

function Fn1 (value) {    Console.log (value)} function fn2 (value) {    fn1 ("fn2 says:" + value);    return false;}

You can use these two methods as callback functions, add them to the $.Callbacks list, and call them in the following order:

var callbacks = $. Callbacks (); Callbacks.add (FN1); Outputs:foo!callbacks.fire ("Foo!"); Callbacks.add (FN2); outputs:bar!, Fn2 says:bar!callbacks.fire ("bar!");

The result of this is that when you construct a complex list of callback functions, it is easy to change. You can pass in the required parameters to these callback functions as needed.

In the example above, we used $.Callbacks() two methods: .add() and .fire() . Add () Adds a new callback function to the list of callback functions, fire () can pass parameters to the callback function, and execute the callback function.

Design ideas:

First crossing the demo of the network, involving the Add and fire method, familiar with the design model of the children's shoes, a glance, in fact, is based on the release of the Observer pattern design of the subscription

Behind the PUB/SUB (Observer pattern), the general idea is to enhance loose coupling in the application. is not a single object invocation on a method of another object. An object acts as an observer of the activity of a particular task or another object, and notifies the observer when that task or activity occurs. The observer is also called the Subscriber (Subscriber), which points to the observed object, both by the Observer (Publisher or subject). When an event occurs, the Observer (publisher) notifies the Observer (subscriber)

As $.Callbacks() a demonstration of creating a component, the PUB/SUB system can be implemented using only the list of callback functions. Will $.Callbacks act as a queue

Let me simulate the simplest implementation of the routine.

var Observable = {      callbacks: [],      add:function (FN) {        this.callbacks.push (FN);      },      fire:function ( {        This.callbacks.forEach (function (FN) {          fn ();        })      }  }

Observable.add (function () {
Alert (1)
})
Observable.fire (function () {
Alert (2)
})

Observable.fire (); 1, 2

Constructs an array that holds the callback, such as this.callbacks= [] when adding a callback, pushing the callback into the this.callbacks, and then traversing This.callbacks execution callback.

Also pop up 1 and 2, actually jquery.callbacks how to deal with it?

We look at the source
The entire $. Callbacks has very few source code, it is a factory function that uses a function call (not a new, it is not a class) to create an object, it has an optional parameter flags is used to set the behavior of the callback function. 、

The external interface is the return of self.

The add source on self

Expand
Source

There's a piece of code to take out alone.

Here is an immediately executed add function to add a callback//direct traversal of the passed arguments for push (function add (args) {    Jquery.each (args, function (_, arg) {        var type = Jquery.type (arg);        If the argument being passed is a function, then the push        if (type = = = "function") {            if (!options.unique | |!self.has (ARG)) {  //as $. Callbacks (' unique '), there is no duplicate callback                List.push (ARG) in the list,            }        } else if (Arg && arg.length && Type!== "string") {  //If the passed argument is an array or array-like, continue to call add, from here you can see that the Add argument can have Add (FN), add ([Fn1,fn2]), add (FN1,FN2)            //Inspect recursively            Add (arg);})    ;}) (arguments)

Add method

An argument can be a function, an Array

Callbacks.add (callbacks)
    • Callbacks

      Type: Function, Array

      A function, or an array of functions, to add to the callback list.

If the array is recursive, the private Add function List.push (ARG) is called recursively;

Found no, the principle of design is actually the same as the simple pattern of the above hair

Fire method

Appearance mode self.fire–> self.firewith–> fire

The final execution code is an internal private fire method.

Fire method

The final processed code

list[firingindex].apply (data[0], data[1])

is actually to take out the list of the callback function, execute it, so the whole design of the principle, or in line with what we began to imagine

The specific implementation

$.Callbacks( "once" )

Make sure that this callback list only executes (. Fire ()) once (like a deferred Deferred).

var callbacks = $. Callbacks ("Once"); Callbacks.add (FN1); Callbacks.fire ("foo");  

Self.disable () was called in the fire; Method

Disables callbacks in the callback list. Disable:function () {    list = stack = memory = undefined;    return this;},

$.Callbacks( "memory" )

Keeping the previous value, add the latest value to the back of this list immediately executes the call to any callback (like a deferred Deferred).

var callbacks = $. Callbacks ("Memory");  Callbacks.add (function () {    console.log ("F1");  });  Callbacks.fire (); Output "F1", then the function list has been executed!  Callbacks.add (function () {    console.log ("F2");  //memory effect Here, there is no fire, the same result: F2

When the Add () method is called, if at this point the callbacks queue satisfies fired && firing = False (True execution) && memory (which needs to be specified in the constructor), the Add () in callback function executes immediately , and the parameters of this add-in callback function are stored in the memory variable. The memory variable is used to store the parameters used for the last call to Callbacks.firewith (...) [Context, arguments].

$.Callbacks( "unique" )

Make sure you can add only one callback at a time (so there are no duplicate callbacks in the list)

var f1 = function () {          console.log ("F1");       };       var callbacks = $. Callbacks ();       Callbacks.add (F1);       Callbacks.add (F1);       Callbacks.fire ();         Output  F1 F1       //pass parameter "unique"       callbacks = $. Callbacks ("unique");       Callbacks.add (F1);     //Effective       Callbacks.add (F1);      //Add not to enter       Callbacks.fire (); Output: F1

Note that the Add method does not go to weight by default, such as here Fn1 added two times, fire will trigger two times * * * *

It's easy to handle here.

if (!options.unique | |!self.has (ARG)) {//Ensure that    List.push (ARG) can be duplicated;}                }

When adding to the processing queue, judge

$.Callbacks( "stopOnFalse" ):

Interrupt call when a callback returns false

var f1 = function () {    console.log ("F1");    return False  }; Note return false;  var F2 = function () {    console.log ("F2");  };  var callbacks = $. Callbacks ();  Callbacks.add (F1);  Callbacks.add (F2);  Callbacks.fire (); Output f1 F2  callbacks = $. Callbacks ("Memory Stoponfalse");  Callbacks.add (F1);  Callbacks.add (F2);  Callbacks.fire (); Outputs only  F1  callbacks.add (function () {    console.log ("F3");  });//No output, memory has lost its function.  Callbacks.fire (); Re-trigger, output F1

Attached Source:

Jquery.callbacks = function (options) {//Convert options from string-formatted to object-formatted if needed//(    We check in cache first)//by string in Optionscache look for there is no corresponding cache, if no then create one, there is a reference//If the object is jquery.extend deep copy after assigning to options.        options = typeof options = = = "string"?    (optionscache[options] | | createoptions (OPTIONS)): Jquery.extend ({}, Options); var//Last Fire value (for non-forgettable lists) memory,///////Flag to know if list is alre simultaneous Ady fired fired,//The function in the list has been callback at least once//Flag to know if list is currently firing firing,//list of functions  Callback in//first callback to fire (used internally by add and Firewith) Firingstart,//start of callback//End of  The loop when firing firinglength,//callback at the end of the loop//Index of currently firing callback (modified by remove if needed) Firingindex,//Current callback function index//Actual callback List list = [],//callback function list//Stack of Fire CAlls for repeatable lists stack =!options.once && [],//repeatable callback function stack for controlling parameter list when triggering callbacks/fire callbacks Trigger List of callback functions fire = function (data) {//If the parameter memory is true, record data memory = options.memory &            & data; Fired = true; Tag Trigger callback Firingindex = Firingstart | |            0;            Firingstart = 0;            Firinglength = List.length;            Tag is triggering callback firing = true; for (; list && Firingindex < firinglength; firingindex++) {if (list[firingindex].apply (da                    ta[0], data[1]) = = = False && Options.stoponfalse) {//block future possible due to the callback generated by add Memory = false; To prevent further calls using add break;             Because the parameter stoponfalse is true, exit the loop when there is a callback function return value of false}}//Mark callback End firing = false; if (list) {if (stack) {if (stack.length ) {//Remove from stack head, recursive Fire Fire (Stack.shift ());                }} else if (memory) {//Otherwise, if there is memory list = [];                } else {//to otherwise block callback Self.disable () in the callback list; }}},///Actual Callbacks object//exposed callbacks objects, external interface self = {//A                DD a callback or a collection of callbacks to the list add:function () {///callback lists add a callback or callback to the collection.                    if (list) {//First, we save the current length///We store the currently listed lengths                    var start = List.length;                             (function add (args) {//jquery.each, performs an operation on each object of the list that args passes in Jquery.each (args, function (_, arg) {                            var type = Jquery.type (ARG); if (type = = = "function") {if (!options.unique | |!self.has (ARG)){//Ensure that List.push (ARG) can be repeated; }//If it is a class array or object, recursion} else if (arg && arg.length && ty                            PE!== "string") {//Inspect recursively Add (ARG);                    }                        });                    }) (arguments);                    Do we need to add the callbacks to the//current firing batch?                    If a callback in the callback list is executing, one of the callback functions performs the Callbacks.add action//The last sentence can be abbreviated: if the state of the callbacks.add operation is firing                    Then you need to update the Firinglength value if (firing) {firinglength = List.length;  With memory, if we ' re not firing then//we should call right away} else if (memory) {///If Options.memory is true, memory is the parameter and should beWith the recently added callback function Firingstart = start;                    Fire (memory);            }} return this;                },//Remove a callback from the list//delete function (set) from the list of functions Remove:function () {                        if (list) {Jquery.each (arguments, function (_, arg) {var index; The meaning of the while loop is to use the powerful jquery.inarray to delete the same function reference in the list of functions (without setting a unique condition)//Jquery.inarray Each time the index of the found element is returned as its third argument continues to be looked up until the end of the function list//splice deletes the array element, modifies the array's structure while (                            index = Jquery.inarray (ARG, list, index)) >-1) {List.splice (index, 1); Handle Firing Indexes//When the function list is in the firing state, the main thing is to maintain firinglength and Firgingindex both                          Values//ensures that functions in the function list can be executed correctly when fire (the For loop in the fire requires both values  if (firing) {if (index <= firinglength) {Firi                                nglength--;                                } if (index <= firingindex) {firingindex--;                }                            }                        }                    });            } return this;            },//Check If a given callback is in the list.            If no argument is given, return whether or not the list has callbacks attached//callback function is in the list. Has:function (FN) {return fn? Jquery.inarray (FN, list) >-1:!!            (list && list.length);                },//Remove all callbacks from the list//delete all callback Functions Empty:function () {                list = [];                firinglength = 0;            return this; },//The LISt does nothing anymore//disables callbacks in the callback list.                Disable:function () {list = stack = memory = undefined;            return this;            },//Is it disabled?            No list is disabled disabled:function () {return!list; },//Lock the list in it current state//Lock Lock:function () {stack                = undefined;                if (!memory) {self.disable ();            } return this;            },//Is it locked?            Whether the list is locked Locked:function () {return!stack; },//Call all callbacks with the given context and arguments//Invoke all callback functions with the given context and parameters Firew Ith:function (context, args) {if (list && (!fired | | | stack)) {args = arg s | |                    []; args = [Context, Args.slice? Args.slice (): Args]; If you are callback if (firing) {//pushes parameters into the stack, wait for the current callback to end before calling Stack.push                    (args);                    } else {//otherwise call Fire (args) directly;            }} return this; },//Call all the callbacks with the given arguments//Invoke all callback functions with the given parameters Fire:function ()                {Self.firewith (this, arguments);            return this;            },//To know if the callbacks has already been called at least once/////callback function list is called at least once Fired:function () {return!!            Fired;    }        }; return self;};

Jquery.callbacks () relatively simple, but also no difficulty

The core of the Jquery.callbacks () method is the fire () method, which encapsulates the fire () method as a private method that is not directly accessible in the function

So like memory, firing, fired these states are immutable for external contexts

It is also important to note that if the This object is used in the callback function, it can be used directly to access the public API of the Self object. Of course, you can also specify the reference object for this with Firewith ().

The core idea of Jquery.callbacks () is the PUB/SUB model, which establishes the loosely coupled and efficient communication between programs.

Reprint Aaron Blog----jQuery 2.0.3 Source Analysis callback Object-callbacks

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.