Why is JavaScript blocking the ui update (via jquery) here? - javascript

In this code, why does the css change not complete until the while loop finishes? I know a loop hangs the browser but I would have thought the css change would be synchronous and therefore finish before the while loop even starts.
Bonus Question: Is there any way for me to get that css change to complete before moving to the while loop without giving up control of the javascript thread?
function run() {
var then = +new Date()
, now
;
$('#mydiv').css('display','block');
now = + new Date();
while (now - then < 5000) {
now = +new Date();
}
}
fiddle: http://jsfiddle.net/ezVZT/2/

Browsers don't always update the page immediately. They'll often wait with updates rendered but not painted while scripts execute and batch all the repainting together.
In your code you're applying a change to the styling, but then executing a 5 second loop which will block everything. The CSS change just has to wait.
If you need to wait five seconds before doing something use a setTimeout() call, or since you're using jQuery, look at .delay().

Would something like $elem.addClass('xyz') solve your problem? you can then assign the display: block to your class in css. Maybe that would be faster?

Try the following code. It might work.
function run() {
var then = +new Date()
, now
;
$('#mydiv').css('display','block');
$("#mydiv", window.parent.document).load($("mydiv").html());
now = + new Date();
while (now - then < 5000) {
now = +new Date();
}
}
function reset() {
$('#mydiv').css('display','none');
}

Related

JS Delay Script Not Using setTimeout

This is a follow up question. I have script that I though would work. This script delays my script from running similar to setTimeout. I can't use setTimeout as my software/platform doesn't allow it. So i am looking for a workaround.
function sleep(milliseconds) {
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) {
if ((new Date().getTime() - start) > milliseconds) {
break;
}
}
}
This function delays the script but it also delays all background scripts from running as well. Im trying to delay my script from running so that all background scripts can finish running. The fact that the above stops all scripts from running defeats the purpose and does not alter to execution order.
I need a script that will delay a block of script without delaying all other background scripts so that they can finish running. Please note that my software/platform does not allow setTimeout and that is why I am looking for a workaround. Thanks.

Constantly check if date is in the past

I want to check if selected date is in the past in 'for loop'. But if I use 'for loop' it stops other code from running. How can I constantly check if date is in the past and not stopping other code from running?
for (var now = new Date();;) {
if (selectedDate < now) {
// some code
}
}
console.log('1') // code that's not running.
JavaScript is fully synchronous and single-threaded. Therefore, your code is getting "locked-up" or stuck at the for loop you have referenced.
You need to use setInterval. For example:
// For demonstration purposes.
var selectedDate = new Date();
// The code inside of this function will run every 1 second (or 1,000 milliseconds)
setInterval(function () {
var now = new Date();
if (selectedDate < now) {
console.log("Selected date is in the past!");
}
}, 1000);
console.log('1') // This code runs now because JavaScript is not caught executing the for loop.
Lot of solutions for resolve this problem. You can use an Observable if ou use RXJS. Else you can use a simple interval with an arrow function or a simple funtion and define repeat time interval in millisecond :
setInterval(repeatFunc,intervalInMillisecond);

Javascript loop clicker

I'm trying to make a javascript script running from the urlbar which for each row on a specific page clicks a button (allowing me to change a certain value), then edit that value, then click that button again to confirm. I'm running into a lot of trouble with simultaneity, as it seems to wait to do the first click 5000 ms even tho it's not being told to pause. didn't do the same when i tested the structure replacing things in between pauses with rando alerts
The reason for the pauses is bc there's a short loading animation during which I can't execute code. Anything glaringly wrong in this as-is? I know there's funky stuff w/ closure, but I thought by busywaiting i could get past it but its not.
function pause(milliseconds) {
var dt = new Date();
while ((new Date()) - dt <= milliseconds) { /* Do nothing */ }
}
var q=document.getElementById("MainContent_gvProducts").children[0];
var l=q.children.length;
for(i=1;i<l;i++){
q.children[i].children[0].children[0].click();
pause(5000);
var x=q.children[i].children[7].children[0].value;
pause(1);
x=math.round(x);
pause(5000);
q.children[i].children[0].children[0].click();
pause(5000);
}
Your pause function seems very hacky.
You should use setTimeout() instead, or something similar.
If you can afford to use the latest JS tech, I'd recommand creating a promise with a timeout and using async/await, with something like this :
async function pause(t = 1000) {
return new Promise(resolve => {
setTimeout(() => {
resolve(true)
}, t)
})
}
for(i=1;i<l;i++){
q.children[i].children[0].children[0].click();
await pause(1000)
var x=q.children[i].children[7].children[0].value;
pause(1);
x=math.round(x);
await pause(5000);
q.children[i].children[0].children[0].click();
await pause(5000);
}
Note : your for loop must be placed in an async function.

jQuery addClass/removeClass working during debugging but not regular execution

I'm trying to run through a series of elements and toggle each's opacity for a given amount of time before returning to normal. I've tried using delay, queue, and a sleep function but haven't had any luck. Oddly enough, I just noticed that when I'm in debug mode, things work exactly as expected. However, outside of debug mode things do not work at all. Here's what I'm currently trying to run in a forEach() loop:
$currEl.toggleClass("light");
sleep(1000);
$currEl.toggleClass('light');
Here's the complete code: https://jsfiddle.net/qdzsws7b/
Busy waiting can be dangerous. Try to make "sequence" and "index" global variables, then toggle class with setTimeout.
var currSequence, currIndex;
function playSequence(sequence){
currSequence = sequnece;
currIndex = 0;
changeLight();
}
function changeLight(){
if (currIndex > 0){
$('#' + mapping[currSequence[currIndex - 1]]).toggleClass('light');
}
$('#' + mapping[currSequence[currIndex++]]).toggleClass('light');
if(currIndex < currSequence.length)
setTimeout(changeLight, 1000);
}

How many timers in a window? [duplicate]

I have to use atleast 2 setTimeouts and 1 setInterval. Does this have any dependency on the browser or javascript engine being used?
tl;dr: Don't worry about the cost of timers until you're creating 100K's of them.
I just did a quick test of timer performance by creating this test file (creates 100K timers over and over):
<script>
var n = 0; // Counter used to verify all timers fire
function makeTimers() {
var start = Date.now();
for (var i = 0; i < 100000; i++, n++) {
setTimeout(hello, 5000);
}
console.log('Timers made in', Date.now() - start, 'msecs');
}
function hello() {
if (--n == 0) {
console.log('All timers fired');
makeTimers(); // Do it again!
}
}
setTimeout(makeTimers, 10000); // Wait a bit before starting test
</script>
I opened this file in Google Chrome (v54) on my circa ~2014 Macbook Pro, and went to the Timeline tab in Developer Tools and recorded the memory profile as the page loaded and ran thru 3-4 cycles of the test.
Observations
The timer creation loop takes 200ms. The page heap size starts at 3.5MB pre-test, and levels out at 3.9MB.
Conclusion
Each timer takes ~.002 msecs to set up, and adds about 35 bytes to the JS heap.
On a page you can have as many setTimeouts/setIntervals running at once as you wish, however in order to control each individually you will need to assign them to a variable.
var interval_1 = setInterval("callFunc1();",2000);
var interval_2 = setInterval("callFunc2();",1000);
clearInterval(interval_1);
The same code above applies to setTimeout, simply replacing the wording.
As Kevin has stated, JavaScript is indeed single threaded, so while you can have multiple timers ticking at once, only one can fire at any one time - i.e. if you have one that fires a function which 'halts' in execution, for example with an alert box, then that JS must be 'resumed' before another can trigger I believe.
One further example is given below. While the markup is not valid, it shows how timeouts work.
<html>
<body>
<script type="text/javascript">
function addThing(){
var newEle = document.createElement("div");
newEle.innerHTML = "Timer1 Tick";
document.body.appendChild(newEle);
}
var t1= setInterval("addThing();",1000);
var t2 = setInterval("alert('moo');",2000);
</script>
</body>
</html>
You can use as many as you want. Just remember that JavaScript is single threaded, so none of them can execute in parallel.
var interval_1 = setInterval("callFunc1();",2000); calls eval() which is evil so it's BAD.
Use this instead var interval_1 = setInterval(callFunc1,2000);
And for the question, you may use as many as you want but if all have the same interval between two actions, you better do it this way
var interval = setInterval(function() {
// function1
fct1();
// function2
fct2();
},2000);

Categories

Resources