While testing my answer to Adding HTML5 hidden attribute support to jQuery .toggle() method, I created a JSPerf test to determine how much slower .toggle(function() \[...\]) would be compared to .toggle(). To my amazement, the script with additional processing is reported to execute faster! Besides the results being counter-intuitive, I suspect a problem because I also see the toggling on the screen long after the results have returned.
How can I "fix" my test to get accurate results?
I.e.
$('button').click(function() {
$('#myElement').toggle(function() { alert("called") })
})
The callback function you pass to toggle only gets executed after the toggle action completes. In other words, it’s an asynchronous action, so if you want to measure how long it takes until the callback is fired, use jsPerf’s async/defer feature.
Related
I was doing this test case to see how much using the this selector speeds up a process. While doing it, I decided to try out pre-saved element variables as well, assuming they would be even faster. Using an element variable saved before the test appears to be the slowest, quite to my confusion. I though only having to "find" the element once would immensely speed up the process. Why is this not the case?
Here are my tests from fastest to slowest, in case anyone can't load it:
1
$("#bar").click(function(){
$(this).width($(this).width()+100);
});
$("#bar").trigger( "click" );
2
$("#bar").click(function(){
$("#bar").width($("#bar").width()+100);
});
$("#bar").trigger( "click" );
3
var bar = $("#bar");
bar.click(function(){
bar.width(bar.width()+100);
});
bar.trigger( "click" );
4
par.click(function(){
par.width(par.width()+100);
});
par.trigger( "click" );
I'd have assumed the order would go 4, 3, 1, 2 in order of which one has to use the selector to "find" the variable more often.
UPDATE: I have a theory, though I'd like someone to verify this if possible. I'm guessing that on click, it has to reference the variable, instead of just the element, which slows it down.
Fixed test case: http://jsperf.com/this-vs-thatjames/10
TL;DR: Number of click handlers executed in each test grows because the element is not reset between tests.
The biggest problem with testing for micro-optimizations is that you have to be very very careful with what you're testing. There are many cases where the testing code interferes with what you're testing. Here is an example from Vyacheslav Egorov of a test that "proves" multiplication is almost instantaneous in JavaScript because the testing loop is removed entirely by the JavaScript compiler:
// I am using Benchmark.js API as if I would run it in the d8.
Benchmark.prototype.setup = function() {
function multiply(x,y) {
return x*y;
}
};
var suite = new Benchmark.Suite;
suite.add('multiply', function() {
var a = Math.round(Math.random()*100),
b = Math.round(Math.random()*100);
for(var i = 0; i < 10000; i++) {
multiply(a,b);
}
})
Since you're already aware there is something counter-intuitive going on, you should pay extra care.
First of all, you're not testing selectors there. Your testing code is doing: zero or more selectors, depending on the test, a function creation (which in some cases is a closure, others it is not), assignment as the click handler and triggering of the jQuery event system.
Also, the element you're testing on is changing between tests. It's obvious that the width in one test is more than the width in the test before. That isn't the biggest problem though. The problem is that the element in one test has X click handlers associated. The element in the next test has X+1 click handlers.
So when you trigger the click handlers for the last test, you also trigger the click handlers associated in all the tests before, making it much slower than tests made earlier.
I fixed the jsPerf, but keep in mind that it still doesn't test just the selector performance. Still, the most important factor that skewes the results is eliminated.
Note: There are some slides and a video about doing good performance testing with jsPerf, focused on common pitfalls that you should avoid. Main ideas:
don't define functions in the tests, do it in the setup/preparation phase
keep the test code as simple as possible
compare things that do the same thing or be upfront about it
test what you intend to test, not the setup code
isolate the tests, reset the state after/before each test
no randomness. mock it if you need it
be aware of browser optimizations (dead code removal, etc)
You don't really test the performance between the different techniques.
If you look at the output of the console for this modified test:
http://jsperf.com/this-vs-thatjames/8
You will see how many event listeners are attached to the #bar object.
And you will see that they are not removed at the beginning for each test.
So the following tests will always become slower as the previous ones because the trigger function has to call all the previous callbacks.
Some of this increase in slowness is because the object reference is already found in memory, so the compiler doesn't have to go looking in memory for the variable
$("#bar").click(function(){
$(this).width($(this).width()+100); // Only has to check the function call
}); // each time, not search the whole memory
as opposed to
var bar = $("#bar");
...
bar.click(function(){
bar.width(bar.width()+100); // Has to search the memory to find it
}); // each time it is used
As zerkms said, dereferencing (having to look up the memory reference as I describe above) has some but little effect on the performance
Thus the main source of slowness in difference for the tests you have performed is the fact that the DOM is not reset between each function call. In actuality, a saved selector performs just about as fast as this
Looks like the performance results you're getting has nothing to do with the code. If you look at these edited tests, you can see that having the same code in two of the tests (first and last) yield totally different results.
I don't know, but if I had to guess I would say it is due to concurrency and multithreading.
When you do $(...) you call the jQuery constructor and create a new object that gets stored in the memory. However, when you reference to an existing variable you do not create a new object (duh).
Although I have no source to quote I believe that every javascript event gets called in its own thread so events don't interfere with eachother. By this logic the compiler would have to get a lock on the variable in order to use it, which might take time.
Once again, I am not sure. Very interesting test btw!
In my work, I frequently encounter following situation:
Situation A:
I need to make multiple ajax calls in one function to retrieve data from server. So I have to make callback functions and define a counter to determine whether all the calls get done.
For example , in each of the sub-functions ( with ajax calls), at the end of the done, I would callback to check the counter's value.
ajax.done(funciton(jsResponse){
.......
base.ajaxLoaded++;
base.dataLoaded();
});
then in base function, I check the value:
dataLoaded: function()
{
var _this = this;
if (_this.ajaxLoaded == 4)
{
// all loaded
_self.render();
_this.afterInit();
}
}
Situation B:
There is a modal pop up triggered by the completion of an animation. So, I have following choices:
1) make a setTimeout function with a timer ( estimated the length of animation)
something like:
setTimeout(function(){
window.MYAPP.triggerMymodal();
},1000);
2) set up a interval function to check repeatedly whether a flag's value has changed and I embedded this flag into the animation finish function, to set it true or false.
if this flag true then make my next move and kills this interval.
3) change animation div attributes and check it use interval function.
Situation C:
Use window.print() function to print something and then need detect when it's finish. This has been asked by myself in this:
how to detect window.print() finish
My Question:
In JavaScript, is there a certain kind of method or Technic to deal with those functions which have unknown execution time? or this is just a case by case thing based on what technology you use?
Yes, the modern approach to dealing with this is called Promises. Various libraries implement the concept, which is basically that you can chain together groups of things that need to happen, either is parallel or serial, and then define success and failure outcomes for each of them.
It takes a bit of time to get your head around it but once you do the code is much more straightforward.
I am new to javascript and don't know whether its using stack for keeping trace of function calling .
This is the code i got stuck with
function bounce(nIdx,bMulti)
{
idDivread.style.display='';
initBounceMgr();
cBounceMgr.bounce(document.all.KnlTbl.rows[nIdx].cells[0].procName,bMulti);
readKill();
}
function readKill()
{
idDivread.style.display='none';
}
This bounce function is called by onclick event and i want to show a div as it has image of wait symbol. And this is working but as i want to remove this wait symbol after function call is done i applied this readKill function. But then that image is not coming at all.
Seems that this function get called before these two functions.
What to do to make sure that readkill function get executed after this two function.
They are being called in the order you would expect. The problem probably comes from the fact that if bounce is an animation or similar it probably returns immediately and does the animation asynchronously. So what it is in fact doing is showing the div, starting the bounce, then hiding the div and in the hidden div doing your bounce animation.
Usually methods that run like this will accept a callback parameter. That is a method that is called after they have finished doing what they want. In this case you would pass readKill in as the callback function instead of calling it directly.
I'm not sure what the cBounceMgr object is though so it is impossible to give you exact syntax to use.
I've got a function called compute() that does a bunch of computations and then updates the values of an HTML table, triggered by a click() event. This is not an ajax call, just several for loops.
What I'd like to do is provide a visual indicator that the computation is running. Something like modifying the opacity of the table. I thought that something like the following could work :
$("#mytable").css("opacity", "0.5");
compute();
$("#mytable").css("opacity", "1");
But when I use this code the opacity does not seem to be modified.
Any hint on how to do this ?
Many thanks in advance !
That's because the UI is not updated between the modification of the opacity and the compute(); function. UI is updated once a while, not after every line of code (that would slow everything down).
You can use a timeout to bypass that: setTimeout(compute, 0);.
That way your UI get's updated before running compute(). You do have to put the third line, where you modify the opacity back to 1, in that function because it will run before compute() is done.
$("#mytable").css("opacity", "0.5");
setTimeout(compute, 0);
function compute() {
...
$("#mytable").css("opacity", "1");
}
It might look dirty at first, but it is a genuine way to make sure your UI is updated!
Most likely this is because your compute() function executes so quickly that you don't perceive the opacity changes.
Try to place a break-point in compute(), let us know whether the opacity changed.
All client side implementations of JavaScript are single threaded, so you can't really expect the function-call compute to carry on running while the next statement is being executed.If you want you could use a web worker, though, to sort-of spawn a background thread.
After reading your question a second time, I must say that #tomdemuyt could very well be right: it's very likely that compute executes so quickly that the opacity is changed twice in a split second, so fast that you hardly notice it changing. also, since this is an event handler, you might want to consider this:
function compute(e)
{
$(this).css({opacity:'.5'});
//rest of your code
$(this).css({opacity:'1'});
}
$('#mytable').on('click',compute);
which is just a bit more tidy IMO - it could be that this is not applicable to your code, but just in case...
So with the new ajax things we have to reinitialize our Javascript event handlers every time an ajax call is made, since an ajax call can result in pretty heavy redrawing of the whole page resulting in uninitialized objects.
Have a look at this jsfiddle:
Javascript eventhandler added multiple times to the same object
This is what I have and it seems to work, but since it is going to be used with everything we have: I wanna make sure that it is the right solution.
E.g. the global defined variable
MyCompany.field.bindedOnfocusSelector = MyCompany.field._focusEventHandler.bindAsEventListener(MyCompany.field);
just feels wrong. And it lacks the possibility to hand more function arguments.
As another poster suggested the prototype $(smth).on(event) I have problems to get it working - I remember problems crossbrowser wise (e.g. on IE 8 things didn't work which worked in Firefox) and even in this simpler example jsFiddle problem with on('focus'):
How about you register an ajax responder, and add the methods after a request has completed
Ajax.Responders.register({
onComplete: function(transport) {
MyCompany.field._initTextInputFields();
}
});
UPDATE
Ok, taking into consideration your comment, how about observing the whole page i.e. body and determining if a input event occurred, ex:
$("#body").on("focus", "input[type=text]:not([readonly])", function(event, element) {
// ....
});
I think this will help you as you only add one observer, and never need to remove it, all your logic can be contained.
PS: note that Event.on is only available in prototype 1.7
UPDATE
ok, what if you just check the click, keyboard won't work now though but i think this is a viable solution
Updated Fiddle