Why is setTimeout/setInterval slowing down when i click onto the page? - javascript

I found out that when you use setInterval() or loop setTimeout() functions and then hold click while moving your cursor on the website (like you do when you want to highlight text), the interval is slowed down for some reason (in Firefox). Sometimes it even slowed down when i just moved the cursor while the interval is running.
Here's an example of a "scroll to top" button that uses setInterval in which you can see that: https://jsfiddle.net/6yzhvb07/56/
This seems like no big deal in codes like the one above but when I'm e.g. coding a mobile browsergame, it is a big problem because every long touch input slows the whole game down more than 50% (in Mobile Chrome).
Has anyone encountered that problem yet or know what may cause that?

This is because of how the javascript runtime engine works. JavaScript doesn't support multithreading. JavaScript uses an EventLoop to keep track of all events happing. If a lot of things is happing events gets stacked up and waits to get proccessed.
If you want to understand exatcly how the event loop works and get details on your answer watch this youtube:
What the heck is the event loop anyway?

That's just one of the caveats of using setTimeout and setInterval, they are not supposed to be relied upon for accuracy. This is especially true since the blocking nature of JavaScript's single-threaded event loop makes it impossible to guarantee execution at a specific time. If you need something to happen at a more accurate time then one method would be to do some math with the result of Date.now() (the amount of milliseconds since January 1 1970 UTC) and occasionally clear and re-set the timeout/interval.
If you're using it for a game then I would recommend not using either and instead opt for requestAnimationFrame. This will require you to get the difference in time between frames to mathematically account for any changes.

Related

Properly Await Propagation of InnerHTML to Complete Before Executing Function [duplicate]

I hope I won't make a fool of myself but I'm trying to understand what is happening in those two lines of code:
document.body.innerHTML = 'something';
alert('something else');
What I am observing is that alert shows before HTML has been updated (or maybe it has but the page hasn't been refreshed/repainted/whatever)
Checkout this codepen to see what I mean.
Please note that even putting alert in setTimeout(..., 0) does not help. Looks like it takes more event loops for innerHTML to actually update page.
EDIT:
I forgot to mention I am using Chrome and did not check other browsers. Looks like it's only visible in Chrome. Nevertheless I am still interested why is that happening.
Setting innerHTML is synchronous, as are most changes you can make to the DOM. However, rendering the webpage is a different story.
(Remember, DOM stands for "Document Object Model". It's just a "model", a representation of data. What the user sees on their screen is a picture of how that model should look. So, changing the model doesn't instantaneously change the picture - it take some time to update.)
Running JavaScript and rendering the webpage actually happen separately. To put it simplistically, first all of the JavaScript on the page runs (from the event loop - check out this excellent video for more detail) and then after that the browser renders any changes to the webpage for the user to see. This is why "blocking" is such a big deal - running computationally intensive code prevents the browser from getting past the "run JS" step and into the "render the page" step, causing the page to freeze or stutter.
Chrome's pipeline looks like this:
As you can see, all of the JavaScript happens first. Then the page gets styled, laid out, painted, and composited - the "render". Not all of this pipeline will execute every frame. It depends on what page elements changed, if any, and how they need to be rerendered.
Note: alert() is also synchronous and executes during the JavaScript step, which is why the alert dialog appears before you see changes to the webpage.
You might now ask "Hold on, what exactly gets run in that 'JavaScript' step in the pipeline? Does all my code run 60 times per second?" The answer is "no", and it goes back to how the JS event loop works. JS code only runs if it's in the stack - from things like event listeners, timeouts, whatever. See previous video (really).
https://developers.google.com/web/fundamentals/performance/rendering/
Yes, it is synchronous, because this works (go ahead, type it in your console):
document.body.innerHTML = 'text';
alert(document.body.innerHTML);// you will see a 'text' alert
The reason you see the alert before you see the page changing is that the browser rendering takes more time and isn't as fast as your javascript executing line by line.
The innerHTML property actual does get updated synchronously, but the visual redraw that this change causes happens asynchronously.
The visual rendering the DOM is asynchronous in Chrome and will not happen until after the current JavaScript function stack has cleared and the browser is free to accept a new event. Other browsers might use separate threads to handle JavaScript code and browser rendering, or they might let some events get priority while an alert is halting the execution of another event.
You can see this in two ways:
If you add for(var i=0; i<1000000; i++) { } before your alert, you've given the browser plenty of time to do a redraw, but it hasn't, because the function stack has not cleared (add is still running).
If you delay your alert via an asynchronous setTimeout(function() { alert('random'); }, 1), the redraw process will get to go ahead of the function delayed by setTimeout.
This does not work if you use a timeout of 0, possibly because Chrome gives event-queue priority to 0 timeouts ahead of any other events (or at least ahead of redraw events).

Is innerHTML asynchronous?

I hope I won't make a fool of myself but I'm trying to understand what is happening in those two lines of code:
document.body.innerHTML = 'something';
alert('something else');
What I am observing is that alert shows before HTML has been updated (or maybe it has but the page hasn't been refreshed/repainted/whatever)
Checkout this codepen to see what I mean.
Please note that even putting alert in setTimeout(..., 0) does not help. Looks like it takes more event loops for innerHTML to actually update page.
EDIT:
I forgot to mention I am using Chrome and did not check other browsers. Looks like it's only visible in Chrome. Nevertheless I am still interested why is that happening.
Setting innerHTML is synchronous, as are most changes you can make to the DOM. However, rendering the webpage is a different story.
(Remember, DOM stands for "Document Object Model". It's just a "model", a representation of data. What the user sees on their screen is a picture of how that model should look. So, changing the model doesn't instantaneously change the picture - it take some time to update.)
Running JavaScript and rendering the webpage actually happen separately. To put it simplistically, first all of the JavaScript on the page runs (from the event loop - check out this excellent video for more detail) and then after that the browser renders any changes to the webpage for the user to see. This is why "blocking" is such a big deal - running computationally intensive code prevents the browser from getting past the "run JS" step and into the "render the page" step, causing the page to freeze or stutter.
Chrome's pipeline looks like this:
As you can see, all of the JavaScript happens first. Then the page gets styled, laid out, painted, and composited - the "render". Not all of this pipeline will execute every frame. It depends on what page elements changed, if any, and how they need to be rerendered.
Note: alert() is also synchronous and executes during the JavaScript step, which is why the alert dialog appears before you see changes to the webpage.
You might now ask "Hold on, what exactly gets run in that 'JavaScript' step in the pipeline? Does all my code run 60 times per second?" The answer is "no", and it goes back to how the JS event loop works. JS code only runs if it's in the stack - from things like event listeners, timeouts, whatever. See previous video (really).
https://developers.google.com/web/fundamentals/performance/rendering/
Yes, it is synchronous, because this works (go ahead, type it in your console):
document.body.innerHTML = 'text';
alert(document.body.innerHTML);// you will see a 'text' alert
The reason you see the alert before you see the page changing is that the browser rendering takes more time and isn't as fast as your javascript executing line by line.
The innerHTML property actual does get updated synchronously, but the visual redraw that this change causes happens asynchronously.
The visual rendering the DOM is asynchronous in Chrome and will not happen until after the current JavaScript function stack has cleared and the browser is free to accept a new event. Other browsers might use separate threads to handle JavaScript code and browser rendering, or they might let some events get priority while an alert is halting the execution of another event.
You can see this in two ways:
If you add for(var i=0; i<1000000; i++) { } before your alert, you've given the browser plenty of time to do a redraw, but it hasn't, because the function stack has not cleared (add is still running).
If you delay your alert via an asynchronous setTimeout(function() { alert('random'); }, 1), the redraw process will get to go ahead of the function delayed by setTimeout.
This does not work if you use a timeout of 0, possibly because Chrome gives event-queue priority to 0 timeouts ahead of any other events (or at least ahead of redraw events).

How to check if JavaScript file is yet to loaded or loading

I am doing GUI automation of my website via Selenium (RobotFramework). The problem I am facing is:
When my automation script clicks on some element (button,link etc) which is supposed to perform some action, it dose nothing. This happening randomly. When we test is manually, it works all the time. One observation is, with slower machine/environment, this tends to happen more.
I suspect this is happening either due to some corresponding JS is not loaded yet or if there is any such thing called "action binding" with each elemetnt, has not happened.
Some question
- Is there a way to find out if all the JS calls are over?
- In case action binding happens, has it already bound or not.
Please share if you have any other solution.
do you know what is last to load on the page? This should be very easy to find out via Developer Tools in your browser of choice.
You can then easily use a Wait Until Keyword (there are many variations) to wait until that last item appears as you expect, then continue with your test. Setting the timeout length and interval will help control the overhead of time/performance.
Wait Until Element Is Visible id=finalElement 10 finalElement did not appear on the screen before timeout period
http://robotframework.org/Selenium2Library/Selenium2Library.html - please see the documentation for further examples and options in terms of keywords

Does using setInterval but not actually doing anything cause memory leak?

I have a script that checks whether or not some elements are on the screen and then if there are a certain number of elements are within those elements and if there aren't, it will 'redraw' them. This is used for changing display options on search results where I can't use ajaxEVENT to do it.
Anyway, if the conditions aren't met, and nothing happens, does this cause any memory issues? I have the interval set to run every 1 second, and chances are nobody who's using this script will be on the same page for more than 5 minutes so..
It does cause memory issues because you're running the script all the time. Try binding some event handlers to whatever you can. The best way imo would be to create your own events and trigger them instead.

I don't fully understand JavaScript Threading

Before I dive into the question. Let me state that by Event Loop I am referring to http://en.wikipedia.org/wiki/Event_loop. This is something that browsers implement. For more information, read this: http://javascript.info/tutorial/further-javascript-features/events-and-timing-depth.
This question is hard and long, so, please try to bear with it! And I do appreciate all answers!
So. Now, as I understand it, in JavaScript there is a single main thread (in most browser environments, that is). So, code like:
for (var color = 0x000; color < 0xfff; color++) {
$('div').css('background-color', color.toString(16));
}
will produce an animation from black to white, but you won't see that because the rendering is done after the code has been processed (when the next tick happens -- the browser enters the Event Loop).
If you want to see the animation, you could do:
for (var color = 0x000; color < 0xfff; color++) {
setTimeout(function() {
$('div').css('background-color', color.toString(16));
}, 0);
}
The above example would produce a visible animation, because setTimeout pushes a new event to the browser Event Loop stack which will be processed after there is nothing running (it enters the Event Loop to see what to do next).
It seems that the browser in this case have 0xfff (4095) events pushed into the stack, where each of them are processed with a render process in between them. So, my first question (#1) is that when exactly does the rendering take place? Does it always take place in between the processing of two events in the Event Loop stack?
The second question is about the code in the javascript.info website link I gave you.
...
function func() {
timer = setTimeout(func, 0)
div.style.backgroundColor = '#'+i.toString(16)
if (i++ == 0xFFFFFF) stop()
}
timer = setTimeout(func, 0)
....
My question here is that will the browser push a new "rendering" event to the Event Loop stack every time it reaches the div.style. ... = ... line? But does it not first push an event due to the setTimeout-call? So, does the browser end up in a stack like:
setTimeout event
render event
Since the setTimeout call was processed before the div style change? If that's how the stack looks like, then I would assume the next time the browser enters the Event Loop it will process the setTimeout's callback and end up having:
rendering event
setTimeout event
rendering event
and continue with the rendering event that the earlier setTimeout call produced?
Q1: Not necessarily. Browsers to varying degrees implement optimizations. For example, they may wait to collect several style changes before triggering an expensive recalculation of the layout. So the answer is: depends on the specific browser.
Try this: http://taligarsiel.com/Projects/howbrowserswork1.htm#Render_tree_construction (the document is dated Oct 2009 - i.e. it is sufficiently up to date)
Q2: The rendering is not necessarily the same as the JS execution - that's two different engines. Ths JS engine is not responsible for the rendering, it just interfaces with the render engine. It seems to me the main message for your second question is this independence of the JS from the rendering engine. Remember, a browser (or a webpage) does not need Javascript, their main purpose is to render HTML based on CSS style rules. Javascript is just one way to manipulate the HTML (the DOM tree really) and the style rules.
Note that you can force rendering by reading a style definition - at this point the rendering engine has no choice but process any outstanding style changes, especially if it involves any position changes. That's why one should remove objects from the rendering tree (e.g. by setting display:none - visibility:hidden is NOT enough since the element's size is still considered for layout) before doing a lot of style changes or adding a lot of elements, e.g. when lots of rows are added one by one (a "for" loop) to a table.
Not part of the question at all - but since I just mentioned a difference between display:none and visibility:hidden, that's also a consideration when adding hidden position:absolute elements like dialogs. While there is no visible difference whether an absolutely positioned element is hidden from you using one or the other method, internally there IS a big difference: when hidden using visibility:hidden the element is part of the rendering tree, with display:none it is not. So, if one has such an element that needs to be toggled a lot one should use visibility:hidden, because when the "display" style is switched between "none" and e.g. "block" the browser has to render it first.
The article you mention only considers Javascript. A lot more happens in the browser; reflowing and repainting are/can be triggered by a lot more things; take a look at the following links for more info on this.
http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/
http://www.browserscope.org/reflow/about
I wouldn't use setTimeout for this purpose.
Edit:
As per the comments, the recommended way is to use requestAnimationFrame. As of this writing, this is only available in unstable releases of most browsers. There are however several libraries available providing cross-browser access to it, and fall back to using setTimeout if necessary.
Take a look at this demo for an example working in old browsers, as well as in new ones:
http://paulirish.com/2011/requestanimationframe-for-smart-animating/

Categories