jQuery-1.9.1 Source Analysis Series (10) Event System Architecture _jquery

Source: Internet
Author: User
Tags unique id

It is also a heavy function point.

Analyze the architecture before analyzing the source code to help understand the source code. In fact, before the advent of jquery, Dean Edwards's Cross-browser Addevent () design was already excellent, and the design idea of the jquery event system was based on that idea, so let's analyze the event bindings of Dean Edwards's predecessors first.

A. jquery event prototype--dean Edwards cross-browser addevent () design

Source Code Interpretation

Event Add method function Addevent (element, type, handler) {//guarantee that each of the different event response functions has only one ID if (!handler.$ $guid) handler.$ $guid = add
  event.guid++; 
 Maintains an events attribute to the element, initialized to an empty object. 
 Element.events structure is similar to {"click": {...}, "Dbclick": {...}, "change": {...}}
  if (!element.events) element.events = {}; An attempt was made to remove the object (more like an array) of the current event type, element.events, and assign to handlers//if the object of the current event type type in Element.events is initialized with the var handlers =
  Element.events[type];
     if (!handlers) {handlers = Element.events[type] = {}; If the element already has a response method for the corresponding event, such as having the OnClick method or assigning the element's OnClick method to the handlers 0 element, the handlers structure is://{0:functio
  N (e) {...}}, which is why Addevent.guid is initialized to 1, reserved for 0 of the space;  At this point, the structure of element.events is: {"click": {0:function (e) {...}}, * Omit other event Type/} if (element["on" + type]) {Handlers[0]
  = element["on" + type]; }///handler the current event to handlers, handler.$ $guid = addevent.guid++; Addevent.guid = 1; Must be cumulative starting from 1 Therefore, this is the handlers structure may be {0:function (e) {...}, 1:function () {}, 2:fuNction () {} And so on ...}
  handlers[handler.$ $guid] = handler;
  A handleevent (event) function is defined below to bind this function to the element's type event as an event entry. Note: When the element is click, the Handleevent function will be triggered and the handleevent function will look for element.events and call the corresponding function.
Handleevent can be referred to as "primary listener function" element["on" + type] = Handleevent;
};
Counter addevent.guid = 1; function removeevent (element, type, handler) {//delete the event handler from the hash table if (element.events && Amp
 Element.events[type]) {delete element.events[type][handler.$ $guid];
}
};
  function Handleevent (event) {//compatible IE event = Event | | window.event;
 This is the node in response to the event, which has the events attribute (added in addevent)//Get node corresponding event response function list var handlers = This.events[event.type];
  The Loop response function list executes for (Var i in handlers) {//maintains the correct scope, i.e. this keyword this.$ $handleEvent = handlers[i];
 this.$ $handleEvent (event); }
};

Re-comb the data structure and use an example

<input type= "text" id= "Chua" onclick= "F0 ();" >
function F0 () {...}
Function F1 () {...}
function F2 () {...}
Function F3 () {...}
var dom = document.getElementById ("Chua");
Addevent (DOM, "click", F1);
Addevent (DOM, "change", F1);
Addevent (DOM, "change", F2);
Addevent (DOM, "click", F3);
Addevent (DOM, "Change", F3);

After the addevent () function, the current data structure is:

Element: {
onclick:handleevent (event),//click event's primary listener function
onchage:handleevent (event),//change event's primary listener function 
    events: {
click:{//This is a class array
0:f0,//element an existing event
1:F1,//subscript 1 is actually f1.$ $guid
3:F3//Subscript 3 is actually the f3.$ $guid, it should be noted that each response event has a unique $ $guid as subscript 
...
},
change:{//This is an array
of classes 1:f1,
2:f2
, 3:f3
}
}}

The event system marks $ $guid for each response function (that is, the third parameter handler in addevent (element, type, handler), depending on the order in which the call addevent. Source

Ensure that each different event response function has only one ID
 if (!handler.$ $guid) handler.$ $guid = addevent.guid++;

The $ $guid tag of the final three response functions is

f1.$ $guid = 1
f2.$ $guid = 2
f3.$ $guid = 3

And according to the source code

handlers[handler.$ $guid] = handler;

Then the subscript position of a function in any set of event response functions is fixed. For example, the click and Change events call F3 as the response event, so the F3 in Element.events.click and Element.events.change are f3.$ $guid = 3; ie element.events.click[3] = element.events.change[3] = F3.

This time the assumption adds an additional event binding: Addevent (DOM, "Focus", F3); then element.events.focus[3] = F3; This is also the convenience of an object compared to an array, the array is not possible without subscript 0,1,2 is directly 3, But the object can, at this point, 3 is an attribute name for the object.

This design, in fact, already has the embryonic form of the jquery event system, including several of the most important features:

1 All events on the element will be saved to the Element.events property, not directly to the element; Such an event can have countless response functions.

2) Handleevent as the "primary listener" for all events of element, having all functions on the unified management element.

3 All browsers support element["on" + Type] Event binding mode, Cross-browser compatible.

Well, the idea of Addevent's event structure really makes people feel bright. The following analyzes the event structure of jquery

B. The event structure of jquery

All function add events go into the JQuery.event.add function. The function has two main features: adding events, attaching a lot of event-related information. We are directly on the source code, the source of ideas and Dean Edwards of the Cross-browser compatible event add processing similar.

SOURCE Analysis

Add:function (Elem, types, handler, data, selector) {var tmp, events, T, Handleobjin, Special, Eventhandle, Handleo
 BJ, handlers, type, namespaces, Origtype,//Get cache data corresponding to elem node Elemdata = Jquery._data (elem);
 No data or text/comment nodes cannot attach events (but allow additional normal objects) if (!elemdata) {return;
  }//caller can replace handler if (handler.handler) {Handleobjin = handler via custom data;
  handler = Handleobjin.handler;
 selector = Handleobjin.selector;
 //Ensure that the handler function has a unique ID, which is later used to find/remove the handler function if (!handler.guid) {handler.guid = jquery.guid++; //If this is the first entry, the event structure of the initialization element and the main event response entry if (!
 events = elemdata.events)) {events = Elemdata.events = {}; } if (! ( Eventhandle = Elemdata.handle)) {eventhandle = Elemdata.handle = function (e) {//When an event is called and the page has been unloaded, discard the jquery.event.
   Trigger () Second event, return typeof JQuery!== core_strundefined && (!e | | jQuery.event.triggered!==)?
  JQuery.event.dispatch.apply (Eventhandle.elem, arguments): undefined;
  }; To prevent IE non-elem as a feature of the handle functionMemory leaks caused by local events Eventhandle.elem = Elem; }//Multiple events using a space-separated processing//such as jquery (...).
  Bind ("MouseOver mouseout", FN); Core_rnotwhite =/\s+/g; matching white space character types = (Types | | ""). Match (core_rnotwhite) | |
  [""];
  t = types.length; while (t--) {//rtypenamespace =/^ ([^.] *)(?:\. (.+)|)
  $/; Get namespace and prototype event TMP = RTYPENAMESPACE.EXEC (types[t]) | |
  [];
  Type = Origtype = Tmp[1]; namespaces = (Tmp[2] | | ""). Split (".").
  Sort (); If the event changes its type, use the special event handler to handle the changed event type special = jquery.event.special[Type] | |
  {}; If the selector is defined, determine the Special Event API type, otherwise give him a type = (selector? special.delegateType:special.bindType) | |
  Type Type update based on the new setting Special special = jquery.event.special[Type] | |
  {}; Handleobj throughout the event handling Handleobj = Jquery.extend ({type:type, Origtype:origtype, Data:data, Handler:handle R, Guid:handler.guid, Selector:selector,//in libraries Implementing. Is (). We Use this as POS matching in ' select '//' Needscontext ': New RegExp ("^" + wHitespace + "*[>+~]|:( Even|odd|eq|gt|lt|nth|first|last) (?: \ \ ("+//whitespace +" * (?:-\ \d) \\d*) "+ whitespace +" *\\) |)
   (? =[^-]|$) "," I ")//used to judge intimate relations Needscontext:selector && jQuery.expr.match.needsContext.test (selector),
  Namespace:namespaces.join (".")
  }, Handleobjin); Initializes an event Processor queue if (!) on initial use (!
   handlers = events[Type]) {handlers = events[type] = [];
   Handlers.delegatecount = 0; Non-custom events, if the special event handler returns FALSE, only addeventlistener/attachevent if (!special.setup | | special.setup.call (ELEM, Data, namespaces, eventhandle) = = False) {//Bind the element global event if (Elem.addeventlistener) {Elem.addeventlistene
    R (Type, Eventhandle, false);
    else if (elem.attachevent) {elem.attachevent ("on" + Type, eventhandle);
   ///Custom event binding if (Special.add) {Special.add.call (Elem, handleobj);
   if (!handleobj.handler.guid) {handleObj.handler.guid = Handler.guid; }///Add Event object Handleobj to the processing list of elements, proxy count passAdd if (selector) {handlers.splice (handlers.delegatecount++, 0, handleobj);
  else {Handlers.push (handleobj);
 //tracking that event was used, for event optimization jquery.event.global[type] = true;
//Prevent IE memory leak elem = null; }

Still use examples to illustrate jquery's event structure

<div id= "#center" ></div>
<script>
 function Dohander () {Console.log ("Dohander")};
 function dot () {console.log ("dot");}
 $ (document). On ("Click", ' #center ', Dohander)
 . On ("Click", ' #center ', dot)
 . On ("click", dot);
</script>

After adding the processing link, the event is added to the element, and the corresponding data is added to the cached data of the node. structure is as follows

 Elemdata = Jquery._data (elem); elemdata = {events: {click: {//array[3] 0: {
        data:undefined/{...}, Guid:2,//handler function ID handler:function dohander () {...}, namespace: "",
      Needscontext:false, Origtype: "Click", selector: "#center",//selector, used to distinguish different event source type: "Click"
        } 1: {data:undefined/{...}, guid:3, Handler:function dot () {...}, namespace: "", Needscontext:false, Origtype: "Click", selector: "#center", type: "Click"} 2: {data:undefined, guid:3, Handler:function dot () {...}, namespace: "", Needscontex T:false, Origtype: "Click", Selector:undefined, type: "Click"} delegatecount:2,//Committee The number of events, there are selector is the delegate event Length:3}} handle:function (e) {...} /* Event handling Main entry */{elem:document//is a feature of handle object} 

The processing of jquery is similar to that of Dean Edwards, which adds a GUID to the Cross-browser compatibility event, such as adding GUIDs to each function, and using events objects to store a list of response events, a total event-handling entry handle, and so on.

  What improvements have jquery made?

1 The event data is no longer stored directly on the node, but instead is accessed using the jquery cache system (internally used cache Jquery._data mode)

2 The event delegate: The handler that binds to the current node (in the example the current node is the document root node) does not only contain the event that is handled when the current node triggers the event (click) response (in the example, the corresponding handler function dot when selector is undefined); It also proxies the events handled by other nodes (the #center node in the example) when the event (click) response is triggered (in the example selector is "#center" corresponding to the handling event dohandler and dot);

3 Adds a lot of functional data, such as namespace namespace: This is primarily used in custom event custom triggers, such as $ (document). On ("Chua.click", ' #center ', dot), active trigger $ ("#center"). Trigger ("Chua.click"). There's additional data: I don't see the place being used.

The event structure of jquery is clear. The binding and triggering of events and the principle of delegation are analyzed later.

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.