In a large-scale JavaScript application I have a similar case like this:
var $box = $('#box');
var expensiveOperation = function () {
for (var i = 0; i < 10000; i++) {
for (var j = 0; j < 4500; j++) {
Math.random();
}
}
};
$('#show').click(function () {
$box.show();
expensiveOperation();
});
$('#showDefer').click(function () {
$box.show();
_.defer(expensiveOperation);
});
$('#hide').click(function () {
$box.hide();
expensiveOperation();
});
$('#hideDefer').click(function () {
$box.hide();
_.defer(expensiveOperation);
});
#box {
background-color:red;
width:100px;
height:100px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="box"></div>
<button id="show">show</button>
<button id="showDefer">show defer</button>
<button id="hide">hide</button>
<button id="hideDefer">hide defer</button>
jsFiddle link, just in case: http://jsfiddle.net/oymaterz/5/
I want to either hide or show a DOM element and the perform an expensive operation. For performance reasons, I want to always ensure that the show/hide are executed first (that is, at the top of the execution stack). This is demonstrated in the example I provided (using underscore's defer) and its working fine under the latest version of Chrome. Also, the above example doesn't work on IE11. Hide/show defer its still slow.
However, when I do the same in my application it works only intermittently and strangely IE11 seems to consistently work fine .
Any ideas as to why I get this behaviour?
I found a solution to my problem. Although it is expected that _.defer (of setTimeout 1) should have worked... it wasn't very consistent in my case. So I ended up using the requestAnimationFrame method. Heres the updated version:
var expensiveOperation = function () {
for (var i = 0; i < 10000; i++) {
for (var j = 0; j < 4500; j++) {
Math.random();
}
}
};
var $box1 = $('#box-1');
$('#show-1').click(function () {
$box1.show();
expensiveOperation();
});
$('#showDefer').click(function () {
$box1.show();
_.defer(expensiveOperation);
});
$('#hide-1').click(function () {
$box1.hide();
expensiveOperation();
});
$('#hideDefer').click(function () {
$box1.hide();
_.defer(expensiveOperation);
});
var $box2 = $('#box-2');
$('#show-2').click(function () {
$box2.show();
expensiveOperation();
});
$('#showRequestAnimationFrame').click(function () {
var flag = true;
requestAnimationFrame(function showAnimFrame(){
if(flag) {
$box2.show();
flag = false;
requestAnimationFrame(showAnimFrame);
} else expensiveOperation();
});
});
$('#hide-2').click(function () {
$box2.hide();
expensiveOperation();
});
$('#hideRequestAnimationFrame').click(function () {
var flag = true;
requestAnimationFrame(function showAnimFrame(){
if(flag) {
$box2.hide();
flag = false;
requestAnimationFrame(showAnimFrame);
} else expensiveOperation();
});
});
#box-1 {
background-color:red;
width:100px;
height:100px;
}
#box-2 {
background-color:blue;
width:100px;
height:100px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="box-1"></div>
<button id="show-1">show</button>
<button id="showDefer">show defer</button>
<button id="hide-1">hide</button>
<button id="hideDefer">hide defer</button>
<p></p>
<div id="box-2"></div>
<button id="show-2">show</button>
<button id="showRequestAnimationFrame">show requestAnimationFrame</button>
<button id="hide-2">hide</button>
<button id="hideRequestAnimationFrame">hide requestAnimationFrame</button>
jsFiddle link, just in case: http://jsfiddle.net/oymaterz/6/
It is worth mentioning that the requestAnimationFrame is not supported in IE8. If you want support for that I will suggest use Paul Irish's excellent GIST for cross-browser compatibility.
I hope that this will help someone in similar situation as me. It clearly works fine for me now and it proofed to be a life-saver.