Is there a way in Javascript to time a browser reflow? - javascript

I need to be able to benchmark a particular build of a webkit-based browser and am measuring the length of time it takes to do certain stuff like DOM manipulation, memory limits etc.
I have a test below which records the length of time it takes to simultaneously load in 10 fairly heavy PNG graphics. In code, I need to be able to time how long it takes for the load to finish. I have tried setting
the onLoad function on the dynamic Image object to produce a time in ms. However, as shown in the cap below it is giving an inaccurate reading because the reading it gives is a tiny amount due to it only recording the data transfer part of the load and then there is a considerable (3000+ms) delay for when the images are viewable - looped in blue, this is the browser reflow cycle.
Is there some event in webkit I can use to record when the browser has finished a reflow so that I can benchmark this? I have to be able to record the time in milliseconds in code because the build of webkit I am testing has no developer tools. I am able to observe the difference in Chrome ok but the performance between the two builds differs drastically and I need to be able to quantify it accurately for comparison.

If you are using jQuery, you could try recording the time between document ready and window load, that would give you an approximation.
(function(){
var start, end;
$(document).ready(function(){
start = new Date()
});
$(window).load(function(){
end = new Date();
console.log(end.getTime() - start.getTime());
});
}());
Edit:
Have you taken a look at the Browserscope reflow timer? Basically it checks to see how long it takes for the browser to return control to the JavaScript engine after changes to the dom. According the the page it should work in any browser, although I haven't tested it personally. Perhaps you could adapt the code run during the tests to time the reflow in your page.

Also, you might want to have a look at CSS Stress Test. The bookmarklet is really great for page performance testing. http://andy.edinborough.org/CSS-Stress-Testing-and-Performance-Profiling
How about setting the PNG as a div background-image and running the stress test, it should enable/disable the image multiple times with timings.

Related

Using Chrome DevTools timeline to measure: Function Call, Recalculate Style, Layout and Paint time

I'm building real time time layout.
If server sends packages every 200ms, then Function Call + Recalculate Style + Layout + Paint time must be less than 200ms.
By using performance.mark with performance.measure or just console.time('1') with console.timeEnd('1') i can measure Function Call what is not enough.
Is there any known way how to put some sort of anchors to get and log number that includes Paint?
That will be used for automated performance testing.
Thanks in advance!
It isn't possible to log Paint times using the Console API. It looks as though there was an attempt to integrate this into WebKit several years ago, but this never got implemented. Right now, you can only do CPU profiling using console.profile, but this isn't relevant for you.
You need to explicitly run the Timeline tool to gather Paint profiling data. You could look into using macros to run this. You can export your data into a JSON file, so that you can re-import and compare each one. It's not optimal for automated testing, but I'm not sure of other ways.
This isn't going to include the paint time itself, but requestAnimationFrame will be called just before the paint.
I also tried setTimeout(fn, 0), but it turned out to be called fairly long after the paint.
If all you want to know is that there is some time left at the end of a frame you might be able to use requestIdleCallback.

does DOM rendering happen asynchronously?

I have some code which gets triggered in a callback on mouse scroll on an SVG
which makes some transformations to SVG (for zooming in and out to a point).
For some huge SVGs , the performance is sluggish and I want to improve this
and I am trying to measure the time taken from the time scroll starts till the time rendering is done.
I have the following code
var timerStart = Date.now();
//some calculations
svgElement.setAttribute("transform",newTransform);
console.log("rendered:", Date.now()-timerStart);
However I can see that rendering happens even after the log is printed.
I assumed that DOM manipulations are synchronous(javascript runtime is single threaded), it seems this is not the case?Is there some rendering queue which asynchronously does the rendering?
How can I accurately measure the performance of rendering in such cases?
Rendering doesn't just happen asynchronously, it happens concurrently (i.e. in another thread). So you can't accurately measure it from the JavaScript thread.
However, most modern browsers allow for profiling from the developer tools provided by them, to see what causes each render/layout/reflow and how to optimize your code.

Animating multiple DIV-Elements with JS and the DOM results in a low Framerate

Preface
I just started programming with javascript and I am currently working on this hobby web-site project of mine. The site is supposed to display pages filled with product images than can be "panned" to either the left or right. Each "page" containing about 24 medium sized pictures, one page almost completely fills out an entire screen. When the user chooses to look at the next page he needs to click'n'drag to the left (for example) to let a new page (dynamically loaded through an AJAX script) slides into the view.
The Issue
This requires for my javascript to "slide" two of these mentioned pages synchronously by the width of a screen. This results in a really low framerate. Firefox and Opera lag a bit, Chrome has it especially bad: 1 frame of animation takes approx. 100 milliseconds, thus making the animation look very "laggy".
I do not use jQuery, nor do I want to use it or any other library to "do the work for me". At least not until I know for sure that what I am trying to do can not be done with a couple of lines of self-written code.
So far I have figured out that the specific way I manipulate the DOM is causing the performance-drop. The routine looks like this:
function slide() {
this.t = new Date().getTime() - this.msBase;
if( this.t > this.msDura ) {
this.callB.call(this.ref,this.nFrames);
return false;
}
//calculating the displacement of both elements
this.pxProg = this.tRatio * this.t;
this.eA.style.left = ( this.pxBaseA + this.pxProg ) + 'px';
this.eB.style.left = (this.pxBaseB + this.pxProg) + 'px';
if ( bRequestAnimationStatus )
requestAnimationFrame( slide.bind(this) );
else
window.setTimeout( slide.bind(this), 16 );
this.nFrames++;
}
//starting an animation
slide.call({
eA: theMiddlePage,
eB: neighboorPage,
callB: theCallback,
msBase: new Date().getTime(),
msDura: 400,
tRatio: ((0-pxScreenWidth)/400),
nFrames: 0,
ref: myObject,
pxBaseA: theMiddlePage.offsetLeft,
pxBaseB: neighboorPage.offsetLeft
});
Question
I noticed that when I let the AJAX script load less images into each page, the animation becomes much faster. The separate images seem to create more overhead than I have expected.
Is there another way to do this?
THE JAVASCRIPT SOLUTION
OK, there are two possible things for you to try to speed this up.
First of all, when you modify the style of an element, you force the browser to rerender the page. This is called a repaint. Certain changes also force a recalculation of the page's geometry. This is called a reflow. A reflow always triggers a repaint immediately after it. I think why you're experiencing worse performance with more elements is that each update to each one triggers at least a repaint. What is normally recommended in the case of modifying multiple styles on a single element is to either do them all at once by adding or removing a class, or hide the element, do your manipulations, and then show it, which means only two repaints (and possibly reflows).
It appears that in this particular case, you're probably already doing just fine, as you're only manipulating each item once per iteration.
Second of all, requestAnimationFrame() is good for doing animations on a canvas element, but seems to have somewhat dodgy performance on DOM elements. Open your page in Chrome's profiler to see exactly where it hangs up. Try JUST using setTimeout() to see if that ends up being the case. Again, the profiler will tell you where the hang-ups are. requestAnimationFrame() should be better, but validate this. I've had it backfire on me, before.
THE REAL SOLUTION
Don't do this in JavaScript, if you can at all avoid it. Use CSS transitions and translation to do the animation with a JavaScript function registered as the onTransitionEnd event handler for each animated element. Letting the browser do this stuff natively is almost always faster than any JS code anyone can write.
The only catch is that CSS3 animations are only supported by the newer browers. For your own edification, do it this way. For real, practical applications, delegate to a library. A good library will do it natively, if possible, and fall back to the best way of doing it in JS for the older browsers.
Good link to read regarding this stuff: http://www.html5rocks.com/en/tutorials/speed/html5/

Estimate browser JS engine speed to conditionally disable animations

Is there a standard (accepted/easy/performant) way to determine how fast a client machine renders javascript?
When I'm running web apps (videos, etc) on my other tabs my JS animations slow to a crawl.
If I could detect slowness from my JS, I would use simpler animations to provide a better user experience.
Update:
Removing animations for everyone is not the answer. I am talking about the simplest of animations which will stutter depending on browser / computer. If I could detect the level of slowness, I would simply disable them.
This is the same as video games with dynamic graphics quality: you want to please people with old computers without penalizing those who have the extra processing power.
One tip is to disable those hidden animations. if they are on another tab that is not in focus, what's the use of keeping them animated?
Another is to keep animations to a minimum. I assume you are on the DOM, and DOM operations are expensive. keep them to a minimum as well.
One tip I got somewhere is if you are using image animation manipulation, consider using canvas instead so that you are not operating on the DOM.
Also, consider progressive enhancement. Keep your features simple and work your way up to complicated things. Use the simple features as a baseline every time you add something new. That way, you can easily determine what causes the problem and fix it accordingly.
The main problem you should first address is why it is slow, not when it is slow.
I know this question is old, but I've just stumbled across it. The simplest way is to execute a long loop and measure the start and end time. This should give you some idea of the machine's Javascript performance.
Please bear in mind, this may delay page loading, so you may want to store the result in a cookie, so it's not measured on every visit to the page.
Something like:
var starttime = new Date();
for( var i=0; i<1000000; i++ ) ;
var dt = new Date() - starttime;
Hope this helps.

How to make GIF rotate when the tree is loading in Javascript

I have a tree that gets populated through the web service - this part is super fast, the part that's a bit slower is populating the tree...I have a gif rotating image that rotates while the service is loading. Since I use ajaxStop and ajaxStart trigger, the gif stops rotating after ajax request has completed, which is correct. However, because the loading takes a split second, the gif freezes for that split second which looks unprofessional.
How do I make the gif rotate until the tree is finished loading?
Browsers give a low priority to image refreshing, so in the time your code is manipulating/inserting in the DOM, the browser is busy with that and doesn't have time to repaint the image.
There's not a whole lot you can do, besides optimizing your code so that the processing you're doing with the ajax data is less intensive, or for example if you're getting a list of 1000 items, insert them in the page in intervals of 50, with a small delay between each, so the browser has time to repaint.
YMMV, maybe it looks great as is in Chrome, but freezes for 5 seconds in IE.
Browsers won't typically update images whilst JavaScript code is executing. If you need the spinner to continue animating during DOM population, your population function will have to give up control back to the browser several times a second to let it update the image, typically by setting a timeout (with no delay, or a very short delay) that calls back into the population process, and then returning.
Unfortunately this will usually make your population function much more complicated, as you have to keep track of how far you've got in the population process in variables instead of relying on loops and conditional structures to remember where you are. Also, it will be slightly slower to run, depending on how you're populating the page structures, and if there are click or other events that your application might get delivered half-way through population you can end up with nasty race conditions.
IMO it would probably be better to stop the spinner and then update the DOM. You'll still get the pause, but without the spinner stuttering to a halt it won't be as noticeable. To give the browser a chance to update the spinner after ajaxStop has changed its src, use a zero-delay-timeout-continuation in your AJAX callback function so that on completion the browser gets a chance to display the altered spinner before going into the lengthy population code.
Making this population step faster is definitely worthwhile, if a slightly different topic. (Appending lots of DOM elements one after the other is inherently slow as each operation has to spend more time trudging through list operations. Appending lots of DOM elements all at once via a DocumentFragment is fast, but getting all those DOM elements into the fragment in the first place might not be. Parsing the entire innerHTML at once is generally fast, but generating HTML without injection security holes is an annoyance; serialising and re-parsing via innerHTML+= is slower and totally awful. IE/HTML5 insertAdjacentHTML is fast, but needs fallback implementation for many browsers: ideally fast Range manipulation, falling back to slow node-by-node DOM calls for browsers with no Range. Don't expect jQuery's append to do this for you; it is as slow as node-by-node DOM operations because that's exactly what it's doing.)
While manipulating the DOM on the fly is really tedious for a lot of browser (especially older one) you might want to optimize what you are doing there as much as you can.
Also, another good idea would be to make sure you are running jQuery 1.4 which is a lot faster for doing such operations.
You can see useful benchmark(1.3 vs 1.4) done by the jQuery team that illustrates that here:
http://jquery14.com/day-01/jquery-14

Categories