I added parallax effect to my page. And now I have problems with performance and FPS and many questions :-)
I use transform3d and requestAnimationFrame to realize it (like this recomended http://www.html5rocks.com/en/tutorials/speed/animations/).
My code looks like this:
window.addEventListener('scroll', function() {
latestKnownScrollY = window.scrollY;
});
function updateParallax() {
var y = latestKnownScrollY * 0.4;
element.style.transform = 'translate3d(0, ' + y + 'px, 0)';
requestAnimationFrame(updateParallax);
}
updateParallax();
Sometimes I have warnings like on the screenshot:
Forced reflow is likely performance bottleneck
Call stack points to latestKnownScrollY = window.scrollY.
But why this warning appears only occasionally? I use window.scrollY each scroll event.
Each time you read window.scrollY, you're causing a reflow. It just means that the browser is calculating the styles and layout to give you the value.
It says it's likely a performance issue because it takes time and it is synchronous. If you read, set, read, set, read, set properties, or if you have this kind of thing inside a loop, it will cause a bottleneck until it can redraw the whole page all the times you triggered the reflow. The solution is usually first to read everything you need, then set everything you need to change.
But in your case, it shouldn't be a problem. It says it takes just 0.2 ms and it's doing it just once. Do you notice any performance issue? Like a lag when you scroll?
Related
I'm running an Angular application that is returning two distinct values simultaneously. I'm curious if anyone has seen this:
function updateValues() {
var activeNavButton = pageNavButtons.eq(values.currentPage);
pageNavButtons.removeClass("active");
activeNavButton.addClass("active");
pageNavButtons.each(function () {
var forceRender = $(this).get(0).offsetLeft;
});
var w = 0;
$(".pages button").each(function () {
w = w + $(this).outerWidth(true)
});
var b=0;
completeHandler();
}
This is straightforward as can be. Switch which item is "active", and then force a render refresh. You'll notice none of this code is really doing anything, but thats okay. I left out some of the less important, unrelated stuff.
Yep, I'm frustrated enough that I'm trying to force the render refresh in multiple ways at once.
In the chrome debugger, if you break on this line:
var b = 0
the following occurs:
w = 790 //Watcher
However, if you open the console while the script is still at that break point and literally copy and paste the preceding 4 lines:
var w = 0;
$(".pages button").each(function () {
w = w + $(this).outerWidth(true)
});
It returns 800 for the value of w.
An important thing to note: the .active class gives the selected element a "bold" font, thus changing the element width. I'm positive this is related to the problem but I can't for the life of me figure out what the issue really is.
As you can see, I'm accessing offsetWidth to try to force the browser to update the elements but its not working.
Any ideas? This is driving me absolutely insane.
Okay. This may seem dumb but on large code bases it might not be terribly surprising:
Turns out that the button's base CSS class (a ways up in the hierarchy) had a transition: all 150ms on it.
This caused a delay, which caused widths to return incorrectly as you might expect because, and this is the important part, font weight is included in transition all.
Because of this, the font weight would change 150ms later, and those extra couple of pixels of width (in certain cases) would register "late". No wonder my timers seemed to arbitrarily succeed: I was guessing.
Lesson learned: Don't use transition: all unless you have a good reason. Target the things you want to actually transition.
Hope this helps somebody else! Cheers.
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.
What are the best practices for moving elements with javascript?
Do you use timeouts or intervals?
Is it bad to have timed events for 10 milliseconds, or will it be precise?
Do you move pixel by pixel, or a certain fraction of the total distance?
If you use intervals, how do you stop the interval when the element is in position?
The last two times I've seen motion in javascript have been with jQuery and Raphael.js, neither of which I can understand the source code of. Are there some good tutorials or code examples anywhere? Is there a simple explanation of the methods jQuery uses?
There is a recent function called requestAnimationFrame which runs a function as soon as possible. This is a good practice since it has been made for animation purposes.
The way it works in terms of coding is the same as setTimeout, e.g. when the function finishes you call requestAnimationFrame.
In the function, you fetch the current time to see how the object should be positioned at that time.
You can cancel a pending function it with cancelRequestAnimationFrame, passing the return value of requestAnimationFrame.
Currently this is not cross-browser and the functions are vendor-prefixed, e.g. webkitRequestAnimationFrame for Chrome.
E.g.: http://jsfiddle.net/pimvdb/G2ThU/1/.
var div = document.getElementById('div');
var animation;
function move() {
var time = Math.round((new Date()).getTime() / 10) % 200;
div.style.left = time + 'px';
animation = requestAnimationFrame(move);
}
document.getElementById("start").onclick = function() {
animation = requestAnimationFrame(move);
}
document.getElementById("stop").onclick = function() {
cancelRequestAnimationFrame(animation);
}
Here you can find a good Javascript Animation tutorial:
http://www.schillmania.com/content/projects/javascript-animation-1
But what you said is right. Jquery Animate uses setTimeout, moving the object based in calculations of duration, position and easing.
Intervals are preferable, I believe, because you only set it once in the code rather than once per frame. It only needs to read the code once and reuse it several times, rather than reading it every time it is created.
10ms is a bit short. The computer can natively support intervals of about 16ms, then more precise timers can be used for faster intervals, however these are very power-consuming. IE9 supports both, depending on the computer's power settings, but ideally you shouldn't need anything faster than 50ms (20 FPS).
I like to move a fraction of the total distance, based on the time that has passed since the animation started. This way, no matter what the speed of the computer and browser, the animation will always take the exact same amount of time. Guaranteed.
Something like:
interval = setInterval(function() {
// do stuff
if( /*animation ended*/) clearInterval(interval);
},time);
jQuery is easy for some, but personally I find nothing beats writing it yourself in plain, old JS. Much easier to understand what's going on exactly, rather than relying on some framework to get it right for you.
I have some legacy javascript that freezes the tfoot/thead of a table and lets the body scroll, it works fine except in IE8 its very slow.
I traced the problem to reading the clientWidth property of a cell in the tfoot/thead... in ie6/7 and FireFox 1.5-3 it takes around 3ms to read the clientWidth property... in IE8 it takes over 200ms and longer when the number of cells in the table is increased.
Is this a known bug ? is there any work around or solution ?
I've solved this problem if you are still interested. The solution is quite complex. Basically, you need to attach a simple HTC to the element and cache its clientWidth/Height.
The simple HTC looks like this:
<component lightweight="true">
<script>
window.clientWidth2[uniqueID]=clientWidth;
window.clientHeight2[uniqueID]=clientHeight;
</script>
</component>
You need to attach the HTC using CSS:
.my-table td {behavior: url(simple.htc);}
Remember that you only need to attach the behavior for IE8!
You then use some JavaScript to create getters for the cached values:
var WIDTH = "clientWidth",
HEIGHT = "clientHeight";
if (8 == document.documentMode) {
window.clientWidth2 = {};
Object.defineProperty(Element.prototype, "clientWidth2", {
get: function() {
return window.clientWidth2[this.uniqueID] || this.clientWidth;
}
});
window.clientHeight2 = {};
Object.defineProperty(Element.prototype, "clientHeight2", {
get: function() {
return window.clientHeight2[this.uniqueID] || this.clientHeight;
}
});
WIDTH = "clientWidth2";
HEIGHT = "clientHeight2";
}
Notice that I created the constants WIDTH/HEIGHT. You should use these to get the width/height of your elements:
var width = element[WIDTH];
It's complicated but it works. I had the same problem as you, accessing clientWidth was incredibly slow. This solves the problem very well. It is still not as fast IE7 but it is back to being usable again.
I was unable to find any documentation that this is a known bug. To improve performance, why not cache the clientWidth property and update the cache periodically? I.E if you code was:
var someValue = someElement.clientWidth + somethingElse;
Change that to:
// Note the following 3 lines use prototype
// To do this without prototype, create the function,
// create a closure out of it, and have the function
// repeatedly call itself using setTimeout() with a timeout of 1000
// milliseconds (or more/less depending on performance you need)
var updateCache = function() {
this. clientWidthCache = $('someElement').clientWidth;
};
new PeriodicalExecuter(updateCache.bind(this),1);
var someValue = this.clientWidthCache + somethingElse
Your problem may be related to something else (and not only the clientwidth call): are your updating/resizing anyhting in your DOM while calling this function?
Your browser could be busy doing reflow on IE8, thus making clientwidth slower?
IE 8 has the ability to switch between IE versions and also there is a compatibility mode.
Have you tried switching to Compatibility Mode? Does that make any difference?
I though I had noticed a slow performance also when reading the width properties. And there may very well be.
However, I discovered that the main impact to performance in our app was that the function which was attached to the window's on resize event was itself somehow causing another resize which caused a cascading effect, though not an infinite loop. I realized this when i saw the call count for the function was orders of magnitude larger in IE8 than in IE7 (love the IE Developer Tool). I think the reason is that some activities on elements, like setting element widths perhaps, now cause a reflow in IE8 that did not do so in IE7.
I fixed it by setting the window's resize event to: resize="return myfunction();" instead of just resize="myfunction();" and making sure myfunction returned false;
I realize the original question is several months old but I figured I'd post my findings in case someone else can benefit.
I'm calling a javascript function that sets the opacity of an iframe an unknown amount of times in rapid succession. Basically this tweens the alpha from 0 to 100.
here is the code
function setAlpha(value)
{
iframe.style.opacity = value * .01;
iframe.style.filter = 'alpha(opacity =' + val + ')';
}
My problem is that for the first time it is working in ie (7) and not in firefox (3.02). in Firefox I get a delay and then the contentdocument appears with an opacity of 100. If I stick an alert in it works, so I'm guessing it is a race condition (although I thought javascript was single threaded) and that the setAlpha function is being called before the last function has finished executing.
Any help would be greatly appreciated. I've read the 'avoiding a javascript race condition post' but I think this qualifies as something different (plus I can't figure out how to apply that example to this one).
The issue is that most browsers don't repaint until there is a pause in the javascript execution.
This can be solved by using setTimeout, as others have suggested. However, I recommend using something like jQuery, or any of the javascript libraries to do animations. Running setTimeout 100 times is a bad idea because the length of the animation will vary based on the browser and speed of the user's computer. The correct way to do animations, is to specify how long they should last and check the system time to determine how far the animation should progress.
function fadeIn(elem,animation_length) {
var start = (new Date()).getTime();
var step = function() {
window.setTimeout(function() {
var pct = ((new Date()).getTime() - start)/animation_length;
elem.style.opacity = Math.min(pct,1);
if (pct < 1)
step();
},20);
};
step();
}
[edit:] The code above is only to illustrate how to do animations based on the system clock instead of simple intervals. Please use a library to do animations. The code above will not work on IE, because IE uses "filter:opacity(xx)" instead of "opacity". Libraries will take care of this for you and also provide nice features such as completion events, and the ability to cancel the animation.
Javascript doesn't run across multiple threads so you're safe from race conditions (ignoring upcoming Worker thread support in Safari and Firefox :D ).
Simple question, how are you calling setAlpha multiple times, firefox, safari and opera all coalesce style sheet updates -- eg. they won't repaint or even recalc style info while js is running unless they have to. So they will only paint if JS has completed.
So if you're doing
while(...) setAlpha(...)
they won't update, you'll probably need to use setTimeout to trigger multiple distinct calls to update the style.
An alternative would be to use a library such as jQuery, mootools,etc that i vaguely recall provide a simplified mechanism to do these types of animations and transitions. As an added bonus i believe at least a few libraries will also use webkit transition and animation css rules when available (eg. Safari, and i think the latest firefox builds)
[edit: caveat: i haen't actually used any of these libraries, i only read about what they're supposed to do. My sites render the same in lynx as any other browser because i couldn't design my way out of a paper bag :D ]
Are you using setTimeout or a tight loop? If you're using just a loop to call the function, then switch to using setTimout.
example:
function setAlpha(value)
{
iframe.style.opacity = value * .01;
iframe.style.filter = 'alpha(opacity =' + val + ')';
if(value < 100 ) {
setTimeout(function () {setAlpha(value+1)},20);
}
}
setAlpha(0);
Because you see, it's not just javascript that's single threaded. It's the whole damn browser. If your javascript goes into a tightloop, you hang the whole browser. So the browser pauses waiting for javascript to finish, and doesn't even have a chance to update the screen, while your code is rapidly changing some dom values.
Some browsers are smart enough to delay changes to the DOM until the call stack is empty.
This is a generally a smart thing to do. For example, if you call a function that changes an element to yellow, and immediately call a function that changes the same element back to it's original state, the browser shouldn't waste time making the change, since it should happen so quickly as to be imperceptible to a user.
The setTimeout(func, 0) trick is commonly used to force Javascript to delay execution of func until the call stack is empty.
In code:
function setAlpha(opacity){
some_element.style.opacity = opacity;
}
/**
* This WON'T work, because the browsers won't bother reflecting the
* changes to the element's opacity until the call stack is empty,
* which can't happen until fadeOut() returns (at the earliest)
**/
function fadeOut(){
for (var i=0; i<10; i++){
setAlpha(0.1*i);
}
}
/**
* This works, because the call stack will be empty between calls
* to setAlpha()
**/
function fadeOut2(){
var opacity = 1;
setTimeout(function setAlphaStep(){
setAlpha(opacity);
if (opacity > 0){
setTimeout(setAlphaStep, 10);
}
opacity -= 0.1;
}, 0);
}
All this boils down to being a wonderful excuse to use one of many javascript libraries that handle this tricky stuff for you.
Edit: and here's a good article on the tricky Javascript call stack