📜 ⬆️ ⬇️

jQuery Events from the inside

The article was written as part of a competition among students of the Mail.ru Technopark .
image

I think the jQuery java script library needs no introduction, but just in case, let me remind you that jQuery is designed to speed up development, provide syntax “sugar” for native js, and save developers from cross-platform issues.
Before we talk about how to handle events in jQuery, not to mention the event handling history in the browser.

Event handling on js
Let's remember a little about the history of browsers. The distant 90s were already going; Internet Explorer was not yet the most common browser, but a Netscape Navigator rules ball. It was the developers of Navigator who proposed the first event handling model on js (currently, this model is most often called the DOM Level 0 Event Model).

DOM Level 0 Event Model

This model is characterized by the following main factors:
  • A reference to the handler function is written directly to the property of the dom object. The names of all events have the prefix “on” - onclick, onload, etc.
  • All event parameters are passed to the handler in the form of an Event Object as the first argument in all browsers except IE. In it, the parameters are in window.event.
  • Events can rise from the node at which they occur to the parent, then to the parent of the parent, and so on. This process is commonly referred to as the ascent phase.
  • It is not possible to install multiple handlers for a single event on an element.

The handler function can be assigned to the property of a DOM element both in the js script and directly in the HTML markup:
ScriptHTML
var element = document.getElementById('id'); element.onmousemove = function (e) { /* … */ }; 
 <a onclick="return{'b-link':{}}" >...</a> <body onresize="onBodyResize()" >...</body> 

It is worth noting that, although this model was not standardized by the W3C, it is supported by all modern browsers (at least on the desktop). And this model is still used. Examples (HTML) are taken from yandex.ru and vk.com.
The model is simple, like a penny, but life does not stand still ...

DOM Level 2 Event Model

image

In 2000, the W3C released the DOM Level 2 Event Model specification, which can be characterized as follows:
  • installation of the handler using the addEventListener method (removal using removeEventListener);
  • on prefix in event names is not used;
  • Event Object is similar to DOM Level 0 Event Model;
  • unlimited number of listeners of the same event on the element;
  • ascent phase from DOM Level 0 Event Model;
  • a capture phase is added, preceding the ascent, in which the event descends from the root element of the DOM tree down to the element in which the event occurred.

The registration method for processing has the following syntax addEventListener (eventType, listener, [useCapture = true]):
  • eventType - event type ('click', 'change', etc.);
  • listener - reference to the handler function;
  • useCapture is a Boolean variable that determines which phase we subscribe to (true - capture, false - ascent).

Then the subscription to change the size of the browser window is:
 window.addEventListener('resize', function (event) { /* … */ }); 

')
Internet Explorer Event Model

Developers from Microsoft have always gone their own way and before IE 9, the versions did not support the generally accepted event model, but they had their own, with blackjack atachEvent and detachEvent.
This model is similar to the DOM Level 2 Event Model, but has a number of differences (there are many others, but these are the most basic):
  • attachEvent and detachEvent methods for installing and removing handlers, respectively;
  • the prefix 'on' in the names of the events;
  • no capture phase.


Total

Taking into account the differences between browsers is painfully painful, but not necessary! We do not forget that we faced all these problems before us - in particular, this is why the jQuery library appeared.

Event handling with jQuery


Here and further, under jQuery, we will understand jQuery 1.10.2, the current version from branch 1.0.
When we use jQuery, we can safely forget about the differences between addEventListener and attachEvent and much more, because the library provides the following for the developer:

So, in jQuery, there are many methods with which you can subscribe to event handling:

There are three ways to unsubscribe from the event: unbind (for bind, click and the like), undelegate and off .
But…
image

jQuery is not only the abstraction level for us from addEventListener and attachEvent, and not only normalizes the Event Object.
Under the hood, jQuery has a vast layer of code consisting of:

First things first.

jQuery.event


Many have already figured out how jQuery works from the inside (for example, here ), but for some reason the event handling mechanism was bypassed. So let's fill this gap.
Event processing from the point of view of a library user goes through three stages:
  1. setting an event handler — calling the bind method, etc.
  2. event handling - all the magic that jQuery performs before the moment when it transfers the normalized Event Object to “our” handler;
  3. deleting an event handler — calling the unbind method, etc.


Special Event API

The jQuery library provides third-party code with the ability to influence the processing of events. In the depths of the library is an object jQuery.event.special; its keys are the names of events, the processing of which we want to intervene, and the value can be an object with the following properties:

It is possible both to interfere with the mechanism of processing existing events and to create one’s own. This is how you can create a pushy event that actually responds to the standard click:
 jQuery.event.special.pushy = { bindType: "click", delegateType: "click" }; 

In addition to the above, there are other possible properties, the purpose of which can be found on the corresponding page .
Later in the article, it will be shown at which moments jQuery transfers control to certain special-methods, and how exactly you can influence the course of event handling.

Install handler

image

Let's imagine that we execute the code
  $('div').click(function (e) { /* ... */ }); 
along with jQuery. Let us examine what happens at each stage.
External handler . In order to handle the event, you must create a handler, get a link to it and pass it to any jQuery method that is responsible for installing the handler. What we actually did was by creating a function using fucntion (e) {/ * ... * /} and calling the click method with it as a parameter.
Methods bind, one, delegate, etc. Our handler falls into one of these methods, inside of which, with a different set of parameters, the on method is actually .
The on method consists of a solid set of if-else blocks — processing and ordering of all possible options with which it can be invoked takes place. It is also in the on method that the installation logic of the once triggered handler is implemented (the one method). Finally, the method each is called for the current jQuery object.
The each method is part of the jQuery core, it is with this method that the library is iterated over the “jQuery set” (see here ). The each method can bypass arrays and objects depending on the interface provided. If the object provides the length property, then the iteration is the same as for the array, which is an excellent example of micro-optimization. So, for each DOM element from the jQuery set, the add method is called.
All subsequent processing takes place in the add method (from the jQuery.event object). At the beginning of each external handler is assigned a unique identifier . For this (and not only) jQuery has a global jQuery.guid counter, which is incremented with each use.
Then a function is created, which we will call the main handler hereinafter, which takes the Event Object as the input and calls the dispatch method.
If the event handler of this event is set for the first time for this item, then a handler queue is created (all external handlers will be written to it) and special.setup is called if it is set for this type of event.
Inside special.setup, a developer can implement his own logic for creating a main handler and subscribing to an event using addEventListener or attachEvent functions, or some other independent logic.
Next, the main handler created by the main handler is subscribed to the required event using addEventListener or atachEvent methods depending on the browser, but this happens only if special.setup is not set or returned false.
Control is then transferred to special.add , if specified. Unlike special.setup, special.add is executed whenever a handler is being installed via jQuery.
And after all this, the external handler passed at the very top enters the handler queue ( link ) and will be called when an event occurs. About this further.

Event handling

image

event occurs - the event occurs in the DOM element and falls into the main handler created by the library (it is subscribed to the event using addEventListener or attachEvent), in which the dispatch method is called.
The dispatch method as the event parameter will receive the original unnormalized Event Object, which is passed to the fix method for normalization.
Inside the fix method, it is checked whether the Event Object is not ready (if it has not been normalized before), and if not, then:

Then special.preDispatch is called, depending on its result, further event handling may end (if preDispatch returns false).
After that, for each handler from the queue that was created during the installation phase, special.handler is called, if it exists. If not, then the handler is called directly by the external handler ( link ).
At the end of the dispatch method, after all the handlers are triggered, special.postDispatch is called. The special.postDispatch method can also be defined in its code, like other special methods.

Remove handler

Removing a handler goes through stages similar to stages from the installation, namely: deleting, starting, for example, with unbind , somehow gets into the off method, then jQuery iterates over the set with the help of each , and in the end it’s not the add method that is called but remove method (thanks, cap).
In the remove method (from jQuery.event), operations are inverse to the add method:

You can influence the process of removing a handler by defining the special.remove and special.teardown functions. remove is called whenever teardown is called when the queue is empty.

Total


We remembered how events were processed in the browser, what happened to the client js code when entering the jQuery arena, and what happens inside this library. A single main handler for the element, the normalization of the Event Object through copying and filtering, a queue of event handlers, and a zoo of installation methods — this is the implementation of the Observer pattern that the creators of jQuery presented us with.
Overboard were at least such important for Event-s topics as delegation, preventDefault (), stopPropagation (), trigger and namespaces. But only source can tell everyone. So github is waiting. :)

Source: https://habr.com/ru/post/209780/


All Articles