Caching is another core design in jquery, and many of jquery's own things depend on caching, such as events, some intermediate variables, animations, and so on. At the same time, he also provides the interface for users to use the interface of the cache, so that users can save their own data on the element node, and help the user to solve the problem of memory leak, naming conflict, which is likely caused by saving data to DOM element directly.
at the same time, HTML5 proposes a function of caching element data through attributes , that is, the data-* attribute , which can save data in the form of a string, and does not conflict with element intrinsic attributes. The jquery cache provides access to the Data-* interface, which is more tightly coupled and more prescriptive than the HTML5 standard.
question: What is the caching implementation principle for different versions of jquery?
Answer: jquery1.x and jquery2.x, jquery3.x are different.
jquery1.x Series, need to be compatible with IE6, IE7 and other early browser, in IE6, IE7 such browser, according to Allen's blog, we can know that DOM elements and JS object reference to each other, is caused by the browser memory leak problem. So the biggest problem in jquery1.x is to prevent memory leaks on IE6, IE7 browsers. In order to avoid memory leaks caused by DOM elements and JS objects referencing each other, jquery must iterate over the problem from the design Solution object. So jquery1.x will need to cache the data on the element, which is stored uniformly in a common storage object (Jquery.cache), and the data in Jquery.cache and the cache holder are linked by a UID. This UID is a number that starts from 1 and is regenerated into a key (Jquery.expando) to store the UID on the cache owner object. This way, the element object does not directly reference the cached object, so there is no memory leak due to circular references.
And jquery2.x, jquery3.x, because there is no need to consider the IE6, IE7 browser, so no longer worry about memory leaks, so the design has made adjustments, Discard the design of saving cached data to Jquery.cache instead of using a unique key to survive, and create a JSON that will save this JSON directly to the cache holder with this unique key.
In addition, a library--zepto, similar to jquery, also provides a caching system. It uses the HTML5 data-* property to save the user-cached object as a string to the data-*, but the disadvantage of this is the type conversion, which cannot save the function and Object objects. In contrast, jquery's caching mechanism does not have this flaw.
question: jquery1.x's cache has been designed very well, jquery2.x (3.x) Why to redesign it?
Answer: jquery1.x Cache Design also has a memory leak problem, mainly Jquery.cache is a global variable, so jquery.cache inside the reference variable, if the reference is not released, it will not be recycled. Although cached variables do not occupy as much memory space as DOM objects, this waste is also a hidden point of the program. Therefore, the DOM object object must be removed from the document, and then through the jquery API will be jquery.cache inside the cache will also be collected . This will give jquery the DOM Operation API implementation of the added difficulty, each involved in the removal of the Node object API needs to do the removal of cache processing, resulting in such as HTML, replacewith, empty等API设计变得更加复杂、执行效率也下降了
. and jquery does not guarantee that when users use JQuery's API to set the cache for an element object, they will also use the jquery API to remove it, rather than the other way. Because the use of jquery APIs and native Dom APIs is a frequent occurrence, jquery1.x cannot guarantee that a memory leak problem cannot occur in this case, such as:
var div = $ ("<div>" // Create a span, put in a div, and give span a cached data {"Data": "Test"} ? var span = $ ("<span>" "Data", "Test" // empties the elements inside the Div, reclaims the span ? span = null ;? div[ 0].innerhtml = ""; // direct use of innerHTML, resulting in $.cache {"Data": "Test"} was not purged, resulting in a memory leak ? // div.html (""); If you use jquery's HTML, the {"Data" in $.cache is cleared: "Test"}
So jquery2.x is not using the jquery1.x Jquery.cache, but rather a simpler design.
As I am looking at the jquery2.2-stable version of the source code, so the following source analysis if not specified version, refers to the jquery2.x version.
question: What are the main parts of jquery's cache implementation?
Answer: the main parts and APIs associated with the jquery cache are as follows:
Name |
External exposure |
Role |
Data |
Whether |
A cached Operation interface class, where all cache operations are done through an instance of data, and the data instance automatically creates a JSON object that holds the cache for the cache owning object. Each instance of the date generates a UID, which we call expando, and the value of this expando is named on the cache holder, so that even if the same object is stored, the data saved by different instances of the instance will not conflict. |
Datapriv |
Whether |
An instance of data that holds the internal information of jquery, if the event, animation, and other data of jquery are saved and retrieved by this accessor. |
Datauser |
Whether |
A data instance that holds the user's stored information through the jquery API |
Jquery.expando |
Is |
jquery's own ID, which is theoretically different for each jquery expando, is used to generate the expando of the accessor data instance. |
Jquery.hasdata |
Is |
Determine if DOM element object, JS object has cached data (including through Datapriv cache and Datauser cache) |
Jquery.data |
Is |
Call Datauser's access directly |
Jquery.removedata |
Is |
Call Datauser's Removedata directly |
Jquery._data |
Is |
Call Datapriv's access directly |
Jquery._removedat |
Is |
Call Datapriv's Removedata directly |
Acceptdata |
Is |
To determine if an object can have a cache, jquery believes that only ordinary objects and element nodes need to cache data, non-elements (element), and DOM elements outside the document, and cannot cache data |
JQuery.fn.data |
Is |
First get the data inside the element's HTML5 data-*, if no more calls Datauser |
JQuery.fn.removeData |
Is |
Loop calls Datauser. Remove method to delete the cached data for key |
The core of the jquery caching section is the cache operation interface data class, which is the underlying implementation of all jquery cache operations. This class has two instances of--datapriv and Datauser. Datapriv is for use by jquery itself, and Datauser is for user-cached data. Externally, jquery exposes the API, the most core of which is jquery.data and jQuery.fn.data, which manipulate ordinary JS objects and Dom objects (jquery supports only element objects), which manipulate jquery objects.
question: What is the generation algorithm for expando?
Answer: let's look at Jquery.expando first:
jquery.extend ({ // Uniquefor each copy of jquery on the page expando: "JQuery" + (ve Rsion + math.random ()). Replace (/\d/g, "" ),}
The algorithm that generates Jquery.expando contains the version of jquery and the random number so that multiple instances of jquery under the same window do not conflict as much as possible.
Then look at the constructor of the accessor data:
function Data () { this. expando = Jquery.expando + data.uid++;}
There is a public attribute in data--uid, each time a data instance is created, the UID is added one and the expando of the data instance is generated with this UID and Jquery.expando. This maximizes the assurance that multiple instances of data on a single page of the jquery instance will not conflict with each other.
Questions:How does data work?
A:the main features of data include the following:
1. Create an object for the specified object that holds the cache, and assign the map object to the specified object with Data.expando as key. And through Acceptdata, for a DOM object of non-element type and document, the data instance is not cached for it.
function Acceptdata (owner) { / / accepts only: // -Node / / -node.element_node // -node.document_node // -Object // -any return Owner.nodetype = = = 1 | | Owner.nodetype = = 9 | | ! (+owner.nodetype);}
2. Provides an API for keys, value operations such as GET, set, and access through overloaded setter and getter. It is important to note that some browsing does not support deleting member variables of DOM objects, so jquery uses assignment undefined instead of delete operations
//Remove The expando if there ' s no more dataif(key = = = Undefined | |jquery.isemptyobject (Cache)) { //support:chrome <= 35-45+ //Webkit & Blink Performance suffers when deleting properties //From DOM nodes, so set to undefined instead //https://code.google.com/p/chromium/issues/detail?id=378607 if(owner.nodetype) {owner[ This. expando] =undefined; } Else { Deleteowner[ This. expando]; }}
question: jquery's data has been dealt with in conflict, so when we use jquery, do we need to consider the situation of cache conflict?
A: The answer is needed because we cannot create the data instance ourselves, the user can use the cache can only be executed by the data instance of Datauser, so jquery's data conflict prevention mechanism is only for jquery internal use, we can not enjoy. So when we use jquery's Jquery.data and JQuery.fn.data interfaces, we need to do our own conflict-prevention processing. Especially for the development of jquery plug-ins, do not want the plug-in cache and the plugin's user cache key conflict, so you have to add a namespace, the note is recommended to use a plug-in jquery name prefix, such as:
(function ($, global, undefined) { $.fn.extend ({ function (option) { returnthis. All (function () { // Development plugin, If you want to use data to save, the original key is preceded by the name of the control to prevent conflict $ (this). Data ("Myplugin:key", plugindata); }) } })}) (Jquery,window)
question: What is the difference between Jquery.data and jQuery.fn.data?
A: They are two APIs in different dimensions, one for the jquery object and one for the JS object (object and Dom objects), with the following specific usage:
// JQuery.fn.data:$ (object). Data (Cachekey,cachevalue) // will be created on object objects Datauser.expando //jquery.data:$.data (object, CacheKey, Cachevalue) // The Datauser.expando is created on the object objects
The above code, the role of the two are basically the same, but there are differences:
1.jquery.fn.data, in addition to querying objects that are cached through Datauser, also accesses HTML5 's data-* data, but is read-only and cannot be modified. The priority is: if the specified key exists in the Datauser data, it will return the Datauser data, otherwise the property will be viewed in data-* the corresponding key data. At the same time, in order to match with HTML5 's data-* cache, data will automatically convert the "X-x-x" key form to "XXX" as the Hump naming form . And these features are only jQuery.fn.data, Jquery.data is not.
When 2.jquery.fn.data is assigned, it iterates through all the JS objects encapsulated by the JQuery object (element object), assigns them values, and jquery.data can only be used on a single object. At the same time jQuery.fn.data a jquery-compliant chain operation, the jquery object is returned, and Jquery.data is the value assigned.
It is important to note that when using the Jquery.data function, the jquery object should not be used as a parameter, as follows:
$.data ($ (object), CacheKey, Cachevalue) // will create a datauser.expando on the $ (object) object, so the call is wrong
Datauser.expando will be created on this object, not object, and then call $.data ($ (object), CacheKey) is not cached, which we do not want. The reason for this is that two times $ (object) is not the same object, but most of the actual operations of the cache are not guaranteed to be able to use the same jquery object, so avoid this.
question: Can you access the data that you set up with these two interfaces?
A: Of course, the answer is yes, because two APIs end up accessing the object's cache by datauser the data instance, so it must be accessible.
var div = $ ("<div>");?? Div.data ("A", "a");? $.data (div[0], "B", "B");?? Console.log (Div.data ("B")) // result b? Console.log ($.data (div[0], "a") // result a
But if key is x-x-x this form, JQuery.fn.data will automatically turn to the hump named hair, and Jquery.data will not:
var div = $ ("<div>");d iv.data ("X-x-x", "Test1"), $.data (div[0], "x-x-x", " Test2 ");
Console.log (Div.data ());
It can be seen that Test1 's key has been changed to the hump naming method, but Test2 does not, this is a difference between the two.
Question: Jquery.hasdata Why is there data in Datapriv also checked?
function (elem) { return datauser.hasdata (elem) | | Datapriv.hasdata (Elem);},
According to the design of the jquery cache, the user's data are in Datauser, the Datapriv cached data should be transparent to the user, the user does not care about Datapriv whether there is data. Then why would jquery.hasdata call Datapriv's hasdata?
A: The reason for doing this is to stay compatible with jquery1.x on the API features, because the jquery1.x series jquery internal caches and user caches are placed in an object, and HasData's function is to detect the existence of this object. Jquery2.x did anti-conflict processing, the cache became two objects--datauser and Datapriv, but for the two version of the exposed API as far as possible to maintain consistency, So instead of re-designing the Jquery.hasdata function, jquery1.x's functional design was preserved. This functional definition is also extended in jquery3.x rather than refactoring to a more reasonable design that detects only datauser.
The API is consistent at the time of upgrade, although it is not conducive to the optimization of API function, but it satisfies the principle of Richter replacement , which facilitates the user to upgrade the version.
jquery2.x Source code parsing (Cache chapter)