Is there a global document frame count? - javascript

Essentially I have some custom controls like sliders and dropdown menus with cool effects.
They rely heavily on getBoundingClientRect to allow for flexibility in CSS, things like changing paddings/font sizes/whatever without throwing off how the control works.
The downside is, getBoundingClientRect is a bit expensive to call so often and due to the way the code is laid out, it sometimes gets called multiple times for the same element in the same frame.
Now I could try and call it only once for each element but it would be a pile of messy if-then sphagetti. Alternatively, I figured I could store the value on a global frame # basis.
Is there a global document frame # available in js?

The question is still open but I found a way to implement my own frame counter
window.render_stats = {
"total_frames" : 0,
};
(function() {
render_stats.total_frames += 1;
requestAnimationFrame(arguments.callee);
})();

Related

How does single threading block DOM manipulation in JavaScript?

I hope my title is correct. I was at an interview today and was stumped by a question dealing with the event loop/ single threading. Here is the code:
function longCB(){
for (var i = 0; i <= 9999; i++){
console.log(i);
}
$('#status').text('hello')
}
$('#status').text('hi')
longCB();
The question was why does the DOM never display 'hi' on the #status div?
Being completely stumped the interviewer explained it was because of single threading in javascript and explained that just by adding a setTimeout to longCB() even if it was set to 0 would make it work. After reviewing the event loop/ event que and call stacks I am still completely stumped why this doesn't work? Shouldn't the line
$('#status').text('hi')
be done before even calling longCB()? What am I missing? Thank you in advanced.
That's because the single thread is also shared by the browser's rendering engine. As long as JS is running synchronously, the page on the screen doesn't get updated. Why? Well, say you had this code:
elem.style.color = 'red';
elem.style.opacity = '1';
elem.textContent = 'Hello';
You wouldn't want the element to show the old text in red, then make it more opaque and then change the text to Hello. You just want the text to immediately change and be red and opaque. This is one reason why the rendering is done only after all JS is run. The other reason has to do with performance. Rendering takes time!
$('#status').text('hi')
longCB();
You are not wrong when you say that the text is set to 'hi' before even calling longCB(), but since the thread is still running JS, the page won't get redrawn just yet. Using setTimeout simply adds the method call on a stack of things to do at some point in the future, and the browser is guaranteed to render between the end of a synchronous script and handling events or timeouts.

Why is ReactJS not performant like raw JS for simple, stupid proof of concept?

Years ago, I heard about a nice 404 page and implemented a copy.
In working with ReactJS, the same idea is intended to be implemented, but it is slow and jerky in its motion, and after a while Chrome gives it an "unresponsive script" warning, pinpointed to line 1226, "var position = index % repeated_tokens.length;", with a few hundred milliseconds' delay between successive calls. The script consistently goes beyond an unresponsive page to bringing a computer to its knees.
Obviously, they're not the same implementation, although the ReactJS version is derived from the "I am not using jQuery yet" version. But beyond that, why is it bogging? Am I making a deep stack of closures? Why is the ReactJS port slower than the bare JavaScript original?
In both cases the work is driven by minor arithmetic and there is nothing particularly interesting about the code or what it is doing.
--UPDATE--
I see I've gotten a downvote and three close votes...
This appears to have gotten response from people who are (a) saying something sensible and (b) contradicting what Pete Hunt and other people have said.
What is claimed, among other things, by Hunt and Facebook's ReactJS video, is that the synthetic DOM is lightning-fast, enough to pull 60 frames per second on a non-JIT iPhone. And they've left an optimization hook to say "Ignore this portion of the DOM in your fast comparison," which I've used elsewhere to disclaim jurisdiction of a non-ReactJS widget.
#EdBallot's suggestion that it's "an extreme (and unnecessary) amount of work to create and render an element, and do a single document.getElementById. Now I'm factoring out that last bit; DOM manipulation is slow. But the responses here are hard to reconcile with what Facebook has been saying about performant ReactJS. There is a "Crunch all you want; we'll make more" attitude about (theoretically) throwing away the DOM and making a new one, which is lightning-fast because it's done in memory without talking to the real DOM.
In many cases I want something more surgical and can attempt to change the smallest area possible, but the letter and spirit of ReactJS videos I've seen is squarely in the spirit of "Crunch all you want; we'll make more."
Off to trying suggested edits to see what they will do...
I didn't look at all the code, but for starters, this is rather inefficient
var update = function() {
React.render(React.createElement(Pragmatometer, null),
document.getElementById('main'));
for(var instance in CKEDITOR.instances) {
CKEDITOR.instances[instance].updateElement();
}
save('Scratchpad', document.getElementById('scratchpad').value);
};
var update_interval = setInterval(update, 100);
It is doing an extreme (and unnecessary) amount of work and it is being done every 100ms. Among other things, it is calling:
React.createElement
React.render
document.getElementById
Probably with the amount of JS objects being created and released, your update function plus garbage collection is taking longer than 100ms, effectively taking the computer to its knees and lower.
At the very least, I'd recommend caching as much as you can outside of the interval callback. Also no need to call React.render multiple times. Once it is rendered into the dom, use setProps or forceUpdate to cause it to render changes.
Here's an example of what I mean:
var mainComponent = React.createElement(Pragmatometer, null);
React.render(mainComponent,
document.getElementById('main'));
var update = function() {
mainComponent.forceUpdate();
for(var instance in CKEDITOR.instances) {
CKEDITOR.instances[instance].updateElement();
}
save('Scratchpad', document.getElementById('scratchpad').value);
};
var update_interval = setInterval(update, 100);
Beyond that, I'd also recommend moving the setInterval code into whatever React component is rendering that stuff (the Scratchpad component?).
A final comment: one of the downsides of using setInterval is that it doesn't wait for the callback function to complete before queuing up the next callback. An alternative is to use setTimeout with the callback setting up the next setTimeout, like this
var update = function() {
// do some stuff
// update is done to setup the next timeout
setTimeout(update, 100);
};
setTimeout(update, 100);

Stop Body Rotation in PhysicsJS

I'm looking for the best practice approach to stop PhysicsJS bodies from being able to rotate.
I have tried cancelling the body's rotational velocity. Yet this does not seem effective on the step as the body still somehow sneaks in some rotation. Combining this with setting the body's rotation manually seems to work at first:
world.on('step', function(){
obj.state.angular.pos = 0;
obj.state.angular.vel = 0;
world.render();
});
However in the past I have experienced a lot of bugs related to this method. Seemingly to do with the object being allowed to rotate just slightly before the step is called, which causes it to be "rotated" very quickly when its body.state.angular.pos is set back to zero. This results in objects suddenly finding themselves inside the subject, or the subject suddenly finding itself inside walls/other objects. Which as you can imagine is not a desirable situation.
I also feel like setting a body's rotation so forcefully must not be the best approach and yet I can't think of a better way. So I'm wondering if there's some method in PhysicsJS that I haven't discovered yet that basically just states "this object cannot rotate", yet still allows the body to be treated as dynamic in all other ways.
Alternatively what is the "safest" approach to gaining the desired effect, I would be happy even with a generic guide not tailored to physicsJS, just something to give me an idea on what is the general best practice for controlling dynamic body rotations in a simulation.
Thanks in advance for any advice!
The key to accomplishing this is to ensure that you put the body to sleep first and then immediately wake it up, afterward setting the angular velocity to zero.
So for example, what I've been doing to prevent bodies that have collided from rotating was:
world.on('collisions:detected', function(data, e) {
var bodyA = data.collisions[0].bodyA,
bodyB = data.collisions[0].bodyB;
bodyA.sleep(true);
bodyA.sleep(false);
bodyA.state.angular.vel = 0;
bodyB.sleep(true);
bodyB.sleep(false);
bodyB.state.angular.vel = 0;
});
I've also seen this accomplished by increasing the mass of the bodies in question to a ridiculously high number, but this would have possible side effects that you may not desire.

Do JavaScript bindings take up memory while not in use?

I have a calendar that I've built, and on clicking a day on the calendar, a function is run. You can go month to month on the calendar, and it generates months as it goes. Since every day on the calendar, shown or not, is binded to an event using the class of all the "days," I'm worried about the number of "bindings" building up into the thousands.
//after a new month is generated, the days are rebound
TDs.off("mousedown");
TDs = $(".tableDay");
TDs.on("mousedown", TDmouseDown);
While I was learning C#/Monogame, I learned about functions that repeat very quickly to update game elements. So, I was wondering if JavaScript works in the same manner. Does the JavaScript engine repeatedly check every single event binding to see if it has occurred? So a structure something like this:
function repeat60timesPerSecond(){
if(element1isClicked){ //blah }
if(element2isClicked){ //blah }
if(element3isClicked){ //blah }
}
Or is JavaScript somehow able to actually just trigger the function when the event occurs?
In short: Do JavaScript bindings take up memory solely by existing?
My (inconclusive) research so far:
I have made several attempts at answering this question on my own. First, I did a jsperf test. Apart from the obvious problems with consistency in my test, the test didn't actually test this question. It primarily tested if unbinding nothing was faster than unbinding something. Rather than how much memory the actual bindings take up after creation. I couldn't come up with a way to test this using this testing service.
I then googled around a bit, and found quite a bit of interesting stuff, but nothing directly answering this question in clear terms. I did come across this answer, which suggests using a single event binding of the event container in a similar situation.
UPDATE:
Right after posting this, I thought of a possible way to test this with local JS:
function func(){
console.log("test");
}
for(x=1;x<1000;x++){
$('#parent').append("<div id='x"+x+"' class='child'></div>");
$("#x"+x).on("mousedown", func);
}
console.time("timer");
for(i=1;i<1000000;i++){
q = Math.sqrt(i);
if(q % 1 == 0){
q = 3;
}
}
console.timeEnd("timer");
After playing around with this(changing what the for loop does, changing the number of iterations on both for loops, etc.) it appears that event bindings take up a VERY small amount of memory.
Yes, they all take up memory, but not very much. There's just one function object. Each element has a pointer to that object, so it's probably something like 4 bytes per element.
As Felix King suggested, you can reduce this by using delegation, as there's just a single binding to a container element. However, the savings in memory is offset by increased time overhead -- the handler is invoked every time the event occurs anywhere in the container, and it has to test whether the target matches the selector to which the event is delegated.

Good (better) substition for setInterval or setTimeout

I've got a masterpage with some nice UI (jQuery) features. One of these options is interefering with my embedded YouTube (or other alike-) objects. On each, in this case, setInterval event the embedded video stops displaying new frames (for like a second).
More detail:
I've got a "polaroid" gallery (in the header) with only 5 100x100 images in it (test: preloading has no effect on performance) and my gallery will show or hide them (fade-in / fade-out) after a period of time. (test: non-animated display:hide or display:block has no effect on performance).
After some testing and I've come to the conclusion that it isn't the "animated" showing or hiding of the pictures, but it's the interval itself (- since altering to display:hide or block had the same result). Perhaps it is my "gallery" "function" on itself ...
function poladroid() {
if (!galleryHasFocus) {
if (galleryMax >= 0) {
galleryCurrent++;
if (galleryCurrent > galleryMax) {
galleryCurrent = 0;
showPictures = !showPictures;
}
if (showPictures) {
$('#pic-' + galleryCurrent.toString()).show("slow");
}
else {
$('#pic-' + galleryCurrent.toString()).hide("slow");
}
}
}
if (!intervalSet) {
window.setInterval("poladroid()", 3000);
intervalSet = true;
}
}
It's not like my function is doing really awkward stuff is it? So, I was thinking I needed a more "loose" interval function.. but is there an option for it?
Ow.. almost forgot to mention it: FireFox and Chrome perform pretty good; using IE (what else) has the most performance problems.
There is no substitute for setInterval/setTimeout - these are the only ways of timing events in browser based ECMAScript.
Its not easy to grasp the real issue here, but I'm guessing the whatever you are triggering using setInterval is heavier than it has to be (as it is jQuery) - you should try to make this more efficient.
If you want an easy to use slideshow, take a look at http://github.com/oyvindkinsey/JsSlideshow - it has a demo here
By the way, do not use a literal as the first argument to setTimeout/setInterval, use a function reference
setInterval(poladroid, 3000);

Categories