📜 ⬆️ ⬇️

Bucket and not the core

What is bad on the example of jq.

Consider the task and its implementation: There are x elements, by clicking on an element, it should change the state. Clicks on an item can be, and most often will be, not alone.


Layout.
A lot of elements - finding the class.
<body> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> <div class="testDiv"></div> </body> 

// undoubtedly ok.
')
Js.
Find by class, hang click, process click, check - uncheck, uncheck - check

jQ
hooked up jQ
The solution of the problem
 $(function(){ $('.testDiv').on('click', function(){ var vedroCache = $(this); if (vedroCache.hasClass('isActiveTestDiv')){ vedroCache.removeClass('isActiveTestDiv'); } else{ vedroCache.addClass('isActiveTestDiv'); } }); }); 


Js
Instead of jq
 // ≈2—3        (function(u){ var J = {}, W = window, D = document, intCache; WJ = J; // search elements if ('getElementsByClassName' in document){ J.$c = function(className, from){ return (from || D).getElementsByClassName(className); } } else{ J.$c = function(className, from){ var cache = (from || D).getElementsByTagName('*'), result = [], i = cache.length, j = -1; for (; i-- ;){ if (cache[i].className.indexOf(className) !== -1){ result[j += 1](cache[i]); } } return result; } } // events if ('addEventListener' in W){ J.eventAdd = function(object, eventName, callback){ object.addEventListener(eventName, callback); }; J.eventDel = function(object, eventName, callback){ object.removeEventListener(eventName, callback); }; } else{ var ieFixEventsNameObjectsCallbacks = [], ieFixEventsObjectsAndCallbacksLength = 0, ieFixEventsHandlers = {}, fixEvent = function(e){ e.preventDefault = function(){ e.returnValue = false; }; e.stopPropagation = function(){ e.cancelBubble = true; }; e.target= e.srcElement; return e; }, ieAddFixEvent = function(object, eventName, callback){ function fix(){ callback.call(object, fixEvent(W.event)); } intCache = ieFixEventsObjectsAndCallbacksLength; ieFixEventsNameObjectsCallbacks[ieFixEventsObjectsAndCallbacksLength] = eventName; ieFixEventsObjectsAndCallbacksLength += 1; intCache += ieFixEventsObjectsAndCallbacksLength; ieFixEventsNameObjectsCallbacks[ieFixEventsObjectsAndCallbacksLength] = callback; ieFixEventsObjectsAndCallbacksLength += 1; intCache += ieFixEventsObjectsAndCallbacksLength; ieFixEventsNameObjectsCallbacks[ieFixEventsObjectsAndCallbacksLength] = object; ieFixEventsObjectsAndCallbacksLength += 1; ieFixEventsHandlers[intCache] = fix; object.attachEvent('on' + eventName, fix); }, ieRemoveFixEvent = function(object, eventName, callback){ for (var i = ieFixEventsObjectsAndCallbacksLength; i-- ;){ if ((ieFixEventsNameObjectsCallbacks[i] === object) && (ieFixEventsNameObjectsCallbacks[i - 1] === callback) && (ieFixEventsNameObjectsCallbacks[i - 2] === eventName)){ ieFixEventsNameObjectsCallbacks[i] = ieFixEventsNameObjectsCallbacks[i - 1] = ieFixEventsNameObjectsCallbacks[i - 2] = u; i = i * 3 - 3; break; } i -= 2; } if (i !== -1){ object.detachEvent('on' + eventName, ieFixEventsHandlers[i]); ieFixEventsHandlers[i] = u; } }; J.eventAdd = function(object, eventName, callback, isNotNeedFix){ if (isNotNeedFix === true){ object.attachEvent('on' + eventName, callback); } else{ ieAddFixEvent(object, eventName, callback); } }; J.eventDel = function(object, eventName, callback, isNotNeedFix){ if (isNotNeedFix === true){ object.detachEvent('on' + eventName, callback); } else{ ieRemoveFixEvent(object, eventName, callback); } }; } // classes J.classHas = function(object, className){ return object.className.indexOf(className) !== -1; //  * }; J.classAdd = function(object, className){ if (!J.classHas(object, className)){ object.className += ' ' + className; } }; J.classDel = function(object, className){ if (J.classHas(object, className)){ object.className = object.className.replace(className, ''); //  * } }; //*    DOM   —   () ! // fast bad ready J.ready = function(callback){ var callbacks = [callback]; function ready(){ var iMax = callbacks.length, i = 0; J.eventDel(D, 'DOMContentLoaded', ready); J.eventDel(W, 'load', ready, true); for (;i < iMax; i += 1){ callbacks[i].call(J); } ready = callbacks = null; J.ready = function(callback){ callback.call(J); } } if ('addEventListener' in W){ J.eventAdd(D, 'DOMContentLoaded', ready); } J.eventAdd(W, 'load', ready, true); J.ready = function(callback){ callbacks.push(callback); } }; }()); 

The solution of the problem
 J.ready(function(){ var J = this, elems = J.$c('testDiv'), i = elems.length; function clickListener(){ J[J.classHas(this, 'isActiveTestDiv') ? 'classDel' : 'classAdd'](this, 'isActiveTestDiv'); } for (;i--;){ J.eventAdd(elems[i], 'click', clickListener); } }); 


Before explaining the bucket’s problems, I would like to note that the solution was set at 350 divs and the next emulation console.time
 if (!('console' in window) || !('time' in console)){ (function(w){ var times = {}, C; if (!('console' in w)){ w.console = C = {}; C.log = function(data){ alert(data); } } else{ C = w.console; } C.time = function(name){ times[name] = new Date().getTime(); }; C.timeEnd = function(name){ if (name in times){ return new Date().getTime() - times[name]; } }; }(window)); } 

on a typewriter
masinka
and in 18.0.1
jQ ≈16ms
J ≈2ms

What's the difference?
By passing a heap of code, the main difference is in the approaches.

Bucket approach
Concept - to realize, apply, i.e.

$ (/ * whatever * /) ./* do something with it * /

We can change jq to any other pieces, but the concept remains the same.

There is a function ready for everything (a bucket), which returns the result of its processing in its shell with a set of actions.

In consequence of what
 //    ,     $('.testDiv').on('click', function(){ var vedroCache = $(this); //             if (vedroCache.hasClass('isActiveTestDiv')){ vedroCache.removeClass('isActiveTestDiv'); } else{ vedroCache.addClass('isActiveTestDiv'); } }); console.log(console.timeEnd('divs')); }); 


No bucket approach (solution set)

/ * solution name * / (/ * task parameters:) * /)

I consider it right if the decision falls on the wrong parameters.

 J.ready(function(){ var J = this, elems = J.$c('testDiv'), //   i = elems.length; function clickListener(){ J[J.classHas(this, 'isActiveTestDiv') ? 'classDel' : 'classAdd'](this, 'isActiveTestDiv'); // ,   } for (;i--;){ J.eventAdd(elems[i], 'click', clickListener); //     } }); 

Develop a topic about the control of specific decisions can be very long.
The conclusion is the following: you need to understand and control as much as possible what is happening with you, without giving everything to the customary bucket.

results

Edited part.
Asked to add conclusions.
What I wanted to say:
1. The main idea.
It is logically bad to think and do as follows.

Magic box, here is my element, make the action of my 5th level dream with it.
That is what you say when writing
$ ('. myElement'). doDoingOfMyDrem (5);
The box should understand what is being asked of it and drive the result into the wrapper.

The following seems to me more correct:
Perform an action of my dreams with an element that can be found in class, using the action of the 5th level.
With the help of J helpers, it will look like this
J.doDoingOfMyDrem (J. $ c ('myElement'), 5);

And if you had a link to the necessary element, for example this in the context of the event handler of the DOM element, it would be like this:
$ (this) .doDoingOfMyDrem (5);
vs
J.doDoingOfMyDrem (this, 5);

2. Time in a good environment on the example of 350 divs, the result differs by 14ms and it is not worth anything, but on mobile the difference is different. On self-service kiosks like kiwi or new payments, which as far as I know in HTML, the third. And on the TV with android?

3. The era of serious web applications has come a long time ago. They consist of a huge number of such small details, combining them into ever larger and larger bundles. Often, real performance problems are felt already in large bundles of ligaments, so the design of a really serious thing must be started with the minimum acceptable units. In my opinion, neither jQ nor many other frameworks set themselves the task of being a serious basis, but they formed the basis for a number of reasons, and that the most terrible things came from framework programmers who do not understand the prices of their magic boxes. As a result, you want to show how you can be different.

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


All Articles