Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Event wanted after page is refreshed

0 views
Skip to first unread message

Stefan Mueller

unread,
Dec 26, 2009, 2:58:43 PM12/26/09
to
I've a html table which is sortable by clicking on the header of each
column.
Because the sorting sometimes takes a couple of seconds I'd like to
prevent that the user can click the header of a column while the sort
function is running.

Here's my approach:
I do at the end of the sort function
sort_end_time = new Date().getTime();
and at the beginning of the sort function I check how much time has
passed after the sort function finished last time
if ((new Date().getTime() - sort_end_time) > 300) {

In this example you have to wait 300 milliseconds before you can sort
the next column. Therefore if you click on a column before the running
sort function has finished doing its job the value of '(new Date
().getTime() - sort_end_time)' is less than 300 milliseconds and the
clicked column will not get sorted. The problem I have now is that
when the last javascript command 'sort_end_time = new Date().getTime
();' is executed the browser needs some time to redraw (refresh) the
table on the screen. If the table has only a couple of rows then it
takes only some milliseconds but if the table has e.g. 2000 rows it
takes in IE more than 1000 milliseconds. Therefore the result of '(new
Date().getTime() - sort_end_time)' is always greater than 300
milliseconds.

Is there any possibility, any event where I can execute the command
'sort_end_time = new Date().getTime();' just after the browser is
ready again (after the refresh)? In my case the command 'sort_end_time
= new Date().getTime();' (the last command of the sort function) is
executed before the browser starts the redraw (refresh).

Stefan

Hans-Georg Michna

unread,
Dec 27, 2009, 5:11:22 AM12/27/09
to
On Sat, 26 Dec 2009 11:58:43 -0800 (PST), Stefan Mueller wrote:

>Is there any possibility, any event where I can execute the command
>'sort_end_time = new Date().getTime();' just after the browser is
>ready again (after the refresh)? In my case the command 'sort_end_time
>= new Date().getTime();' (the last command of the sort function) is
>executed before the browser starts the redraw (refresh).

Stefan,

check http://winhlp.com/node/633 for some basic thoughts about
the rendering to screen and its detection.

But you may be trying to kill a non-existent dragon. JavaScript
execution is single-threaded. No second JavaScript thread can
start before the current one has finished.

Most browsers don't even render to screen, as long as any
JavaScript task is running, with the exception of Opera.

Hans-Georg

JR

unread,
Dec 27, 2009, 8:27:10 AM12/27/09
to
On 26 dez, 17:58, Stefan Mueller <seekw...@yahoo.com> wrote:
> I've a html table which is sortable by clicking on the header of each
> column.
> Because the sorting sometimes takes a couple of seconds I'd like to
> prevent that the user can click the header of a column while the sort
> function is running.

This kind of sorting shouldn't take longer than a few milliseconds.
Maybe the code is not optimized for the browser in which you're
testing it.

> Here's my approach:
> I do at the end of the sort function
>   sort_end_time = new Date().getTime();
> and at the beginning of the sort function I check how much time has
> passed after the sort function finished last time
>   if ((new Date().getTime() - sort_end_time) > 300) {
>
> In this example you have to wait 300 milliseconds before you can sort
> the next column. Therefore if you click on a column before the running
> sort function has finished doing its job the value of '(new Date
> ().getTime() - sort_end_time)' is less than 300 milliseconds and the
> clicked column will not get sorted. The problem I have now is that
> when the last javascript command 'sort_end_time = new Date().getTime
> ();' is executed the browser needs some time to redraw (refresh) the
> table on the screen. If the table has only a couple of rows then it
> takes only some milliseconds but if the table has e.g. 2000 rows it
> takes in IE more than 1000 milliseconds. Therefore the result of '(new
> Date().getTime() - sort_end_time)' is always greater than 300
> milliseconds.
>
> Is there any possibility, any event  where I can execute the command
> 'sort_end_time = new Date().getTime();' just after the browser is
> ready again (after the refresh)? In my case the command 'sort_end_time
> = new Date().getTime();' (the last command of the sort function) is
> executed before the browser starts the redraw (refresh).

You can prevent a code from being called twice using the
'arguments.callee.done' old trick, e.g.:

function sort() {
if (!arguments.callee.done) { // checks the 'done' property of sort
().
return; // exit.
}
// If code doesn't return, do the sort stuff hereafter.
// But in the end of the sorting, don't forget to set
// arguments.callee.done = true;
}

Cheers,
JR

JR

unread,
Dec 27, 2009, 8:43:59 AM12/27/09
to

Sorry, the correct sequence goes below:

function sort() {
if (arguments.callee.done) return;
arguments.callee.done = true;
// do the sort stuff.
arguments.callee.done = false; // in the end.
}

--
JR

David Mark

unread,
Dec 27, 2009, 12:42:46 PM12/27/09
to
On Dec 27, 5:11 am, Hans-Georg Michna <hans-

georgNoEmailPle...@michna.com> wrote:
> On Sat, 26 Dec 2009 11:58:43 -0800 (PST), Stefan Mueller wrote:
> >Is there any possibility, any event  where I can execute the command
> >'sort_end_time = new Date().getTime();' just after the browser is
> >ready again (after the refresh)? In my case the command 'sort_end_time
> >= new Date().getTime();' (the last command of the sort function) is
> >executed before the browser starts the redraw (refresh).
>
> Stefan,
>
> checkhttp://winhlp.com/node/633for some basic thoughts about

> the rendering to screen and its detection.
>
> But you may be trying to kill a non-existent dragon. JavaScript
> execution is single-threaded. No second JavaScript thread can
> start before the current one has finished.
>
> Most browsers don't even render to screen, as long as any
> JavaScript task is running, with the exception of Opera.
>

They all work about the same in that regard. They can re-flow on
exiting execution contexts.

Dr J R Stockton

unread,
Dec 27, 2009, 4:33:24 PM12/27/09
to
In comp.lang.javascript message <2b8192d5-88aa-45df-b72b-4b698a869c00@j1
4g2000yqm.googlegroups.com>, Sat, 26 Dec 2009 11:58:43, Stefan Mueller
<seek...@yahoo.com> posted:

>I've a html table which is sortable by clicking on the header of each
>column.
>Because the sorting sometimes takes a couple of seconds I'd like to
>prevent that the user can click the header of a column while the sort
>function is running.
>
>Here's my approach:
>I do at the end of the sort function
> sort_end_time = new Date().getTime();
>and at the beginning of the sort function I check how much time has
>passed after the sort function finished last time
> if ((new Date().getTime() - sort_end_time) > 300) {


Rather than use Date, would it not be better to do something like

Busy = true
CallLengthySortFunction()
Busy = false

and test Busy at the start of your onClick routines?

That does not address the re-draw time question.

--
(c) John Stockton, Surrey, UK. ?@merlyn.demon.co.uk Turnpike v6.05 MIME.
Web <URL:http://www.merlyn.demon.co.uk/> - FAQish topics, acronyms, & links.
Proper <= 4-line sig. separator as above, a line exactly "-- " (RFCs 5536/7)
Do not Mail News to me. Before a reply, quote with ">" or "> " (RFCs 5536/7)

Stefan Mueller

unread,
Jan 7, 2010, 4:41:14 AM1/7/10
to
On Dec 27 2009, 10:33 pm, Dr J R Stockton

<reply0...@merlyn.demon.co.uk> wrote:
> Rather than use Date, would it not be better to do something like
>
>         Busy = true
>         CallLengthySortFunction()
>         Busy = false
>
> and test Busy at the start of your onClick routines?
>
> That does not address the re-draw time question.

Yes, it would be much better to do something like


Busy = true
CallLengthySortFunction()
Busy = false

But it does not work.

The 'CallLengthySortFunction()' locks the whole javascript engine so
that the onClick event is not executed before the
'CallLengthySortFunction()' has finished. If you click on a column the
onClick event is "cached" and first when the 'CallLengthySortFunction
()' has finished the onClick event gets executed and then 'Busy' is
set False and not True anymore.

That's the reason why I'm trying to do something with the time
function.

However, like you mentioned, even if your solution with 'Busy' would
work I still had the problem that 'Busy = false' (last javascript
command) is executed BEFORE the browser has redrawn (refreshed) the
table on the screen. That means that 'Busy' is False before the user
sees the new sorted table on the screen and that he already can click
on another column before the newly sorted table is displayed.

I need any possibility, any event where I can execute the command
'Busy = false' or in my case to save the time just after the browser
is ready again (after the refresh which sometimes takes several
seconds).

Stefan

David Mark

unread,
Jan 7, 2010, 5:07:38 AM1/7/10
to
On Jan 7, 4:41 am, Stefan Mueller <seekw...@yahoo.com> wrote:
> On Dec 27 2009, 10:33 pm, Dr J R Stockton
>
> <reply0...@merlyn.demon.co.uk> wrote:
> > Rather than use Date, would it not be better to do something like
>
> >         Busy = true
> >         CallLengthySortFunction()
> >         Busy = false
>
> > and test Busy at the start of your onClick routines?
>
> > That does not address the re-draw time question.

There is no such question. ;)

>
> Yes, it would be much better to do something like
>   Busy = true
>   CallLengthySortFunction()
>   Busy = false

That's exactly the same. (?)

> But it does not work.
>
> The 'CallLengthySortFunction()' locks the whole javascript engine so
> that the onClick event is not executed before the
> 'CallLengthySortFunction()' has finished. If you click on a column the
> onClick event is "cached" and first when the 'CallLengthySortFunction
> ()' has finished the onClick event gets executed and then 'Busy' is
> set False and not True anymore.

You are confused. "Cached" user actions are not going to do anything
until you are finished with the above execution. And there's a good
chance that the rendering will be updated on exiting the sort function
(though that is irrelevant). Post a test page that demonstrates your
problem as your descriptions so far can't be accurate.

And forget anything to do with timing. Such strategies are doomed to
fail (if not for you, then for some percentage of your users). ;)

Stefan Mueller

unread,
Jan 11, 2010, 11:04:43 PM1/11/10
to
On Jan 7, 11:07 am, David Mark <dmark.cins...@gmail.com> wrote:
> You are confused.  "Cached" user actions are not going to do anything
> until you are finished with the above execution.  And there's a good
> chance that the rendering will be updated on exiting the sort function
> (though that is irrelevant).  Post a testpagethat demonstrates your

> problem as your descriptions so far can't be accurate.

Here is a testpage:
http://test.seekware.ch/example.html

Please click once on 'Column 1' and after a few seconds the table is
sorted (just click 'Ok' to close the message box).
Click on 'Column 1' again and watch the message box. 'Busy' is false
and 'Difference' shows the time elapsed after the last sorting.
Now click 'Ok' and just again on 'Column 1' (before the sorting has
finished). Your click will be cached and just after the sorting has
finished the message box appears again. 'Busy' is false again and also
'Difference' shows the time elapsed (a couple of milliseconds) after
the last sorting again (this is the time the browser needs to refresh
the table).

> And forget anything to do with timing.  Such strategies are doomed to
> fail (if not for you, then for some percentage of your users).  ;)

I totally agree! I just thought that this could be the only
possibility. But if there's no possibility, no event where I can save
the time just after the browser is ready again it makes no sense.

To sum up: I'm looking for a solution to prevent clicking on a column
header while the table is sorting.
The only solution I figured out is to add the command 'alert("Sorting
done.");' at the end of the sort function because then the cached
mouse clicks get deleted. But I don't want to display such a message
box. Is there perhaps another way to delete these mouse clicks?

Stefan

JR

unread,
Jan 12, 2010, 7:59:47 AM1/12/10
to

The solution is using a flag ('busy') as a property of the sort
method:

function sort() {
if (arguments.callee.busy) { return; }
arguments.callee.busy = true;


// do the sort stuff.

arguments.callee.busy = false;
}

--
JR

Stefan Mueller

unread,
Jan 12, 2010, 2:39:45 PM1/12/10
to
On Jan 12, 1:59 pm, JR <groups_j...@yahoo.com.br> wrote:
> > To sum up: I'm looking for a solution to prevent clicking on a column
> > header while the table is sorting.
> > The only solution I figured out is to add the command 'alert("Sorting
> > done.");' at the end of the sort function because then the cached
> > mouse clicks get deleted. But I don't want to display such a message
> > box. Is there perhaps another way to delete these mouse clicks?
>
> The solution is using a flag ('busy') as a property of the sort
> method:
>
> function sort() {
>   if (arguments.callee.busy) { return; }
>   arguments.callee.busy = true;
>   // do the sort stuff.
>   arguments.callee.busy = false;

Good idea but it doesn't work neither.

I added it to the testpage:
http://test.seekware.ch/example.html

'arguments.callee.busy' is also always false.

Stefan

Jorge

unread,
Jan 12, 2010, 9:12:34 PM1/12/10
to

Stefan,

All you need to do is to wrap the whole thing in a setTimeout
(sortingCode ,0); That will warrant a redraw *before* it executes.
Like this:

elem.onclick= function onclick () {
elem.onclick= null; //trash useless double-clicks
setTimeout(function () {

//Put your sorting code here.

elem.onclick= onclick;
}, 0);
};
--
Jorge.

David Mark

unread,
Jan 13, 2010, 3:38:38 AM1/13/10
to
On Jan 11, 11:04 pm, Stefan Mueller <seekw...@yahoo.com> wrote:
> On Jan 7, 11:07 am, David Mark <dmark.cins...@gmail.com> wrote:
>
> > You are confused. "Cached" user actions are not going to do anything
> > until you are finished with the above execution. And there's a good
> > chance that the rendering will be updated on exiting the sort function
> > (though that is irrelevant). Post a testpagethat demonstrates your
> > problem as your descriptions so far can't be accurate.
>
> Here is a testpage:
> http://test.seekware.ch/example.html

Okay. I glanced at it.

>
> Please click once on 'Column 1' and after a few seconds the table is
> sorted (just click 'Ok' to close the message box).

Yeah, it was more than a few on this machine. You have to break up that
process, using a timeout to fire each in turn. So there's no point in
worrying about how this version behaves.

> Click on 'Column 1' again and watch the message box. 'Busy' is false
> and 'Difference' shows the time elapsed after the last sorting.
> Now click 'Ok' and just again on 'Column 1' (before the sorting has
> finished). Your click will be cached and just after the sorting has
> finished the message box appears again. 'Busy' is false again and also
> 'Difference' shows the time elapsed (a couple of milliseconds) after
> the last sorting again (this is the time the browser needs to refresh
> the table).

So what's the problem? And please lose the alerts as they can foul up
these sorts of tests.

>
> > And forget anything to do with timing. Such strategies are doomed to
> > fail (if not for you, then for some percentage of your users). ;)
>
> I totally agree! I just thought that this could be the only
> possibility. But if there's no possibility, no event where I can save
> the time just after the browser is ready again it makes no sense.

I still don't see what your problem is.

>
> To sum up: I'm looking for a solution to prevent clicking on a column
> header while the table is sorting.

You can't prevent the user from clicking. You are in charge of your own
listners though. So it is up to you...

> The only solution I figured out is to add the command 'alert("Sorting
> done.");' at the end of the sort function because then the cached
> mouse clicks get deleted.

That's an erroneous characterization, regardless of what you observed.
You really need to stop guessing.

> But I don't want to display such a message
> box. Is there perhaps another way to delete these mouse clicks?

There is no way to "delete" mouse clicks. You can, however, consult a
"busy" flag to determine whether to act on them or not. So in a couple
of sentences, what do you perceive the failure to be? And forget about
when the browser re-renders the column headers (that's a red herring).

David Mark

unread,
Jan 13, 2010, 3:40:44 AM1/13/10
to
Jorge wrote:
> On Jan 12, 8:39 pm, Stefan Mueller <seekw...@yahoo.com> wrote:
>> On Jan 12, 1:59 pm, JR <groups_j...@yahoo.com.br> wrote:
>>
>>>> To sum up: I'm looking for a solution to prevent clicking on a column
>>>> header while the table is sorting.
>>>> The only solution I figured out is to add the command 'alert("Sorting
>>>> done.");' at the end of the sort function because then the cached
>>>> mouse clicks get deleted. But I don't want to display such a message
>>>> box. Is there perhaps another way to delete these mouse clicks?
>>> The solution is using a flag ('busy') as a property of the sort
>>> method:
>>> function sort() {
>>> if (arguments.callee.busy) { return; }
>>> arguments.callee.busy = true;
>>> // do the sort stuff.
>>> arguments.callee.busy = false;
>> Good idea but it doesn't work neither.
>>
>> I added it to the testpage:
>> http://test.seekware.ch/example.html
>>
>> 'arguments.callee.busy' is also always false.
>>
>> Stefan
>
> Stefan,
>
> All you need to do is to wrap the whole thing in a setTimeout
> (sortingCode ,0); That will warrant a redraw *before* it executes.

As usual, you have no idea what you are talking about. This has
absolutely nothing to do with any so-called "redraw". Where do you get
this shit?

It's a simple click listener that needs to prevent re-entry in some
cases. How this has turned into a mystery is beyond me. If you can't
solve this one, you can't write anything for browsers.

David Mark

unread,
Jan 13, 2010, 3:46:42 AM1/13/10
to
Hans-Georg Michna wrote:
> On Sat, 26 Dec 2009 11:58:43 -0800 (PST), Stefan Mueller wrote:
>
>> Is there any possibility, any event where I can execute the command
>> 'sort_end_time = new Date().getTime();' just after the browser is
>> ready again (after the refresh)? In my case the command 'sort_end_time
>> = new Date().getTime();' (the last command of the sort function) is
>> executed before the browser starts the redraw (refresh).
>
> Stefan,
>
> check http://winhlp.com/node/633 for some basic thoughts about
> the rendering to screen and its detection.

It has nothing to do with that.

>
> But you may be trying to kill a non-existent dragon. JavaScript
> execution is single-threaded. No second JavaScript thread can
> start before the current one has finished.

Exactly. And, though irrelevant for this case, it should be mentioned
that re-flows are similarly predictable (they happen only on exiting
execution contexts).

>
> Most browsers don't even render to screen, as long as any
> JavaScript task is running, with the exception of Opera.

That's incorrect. They virtually all re-flow on exiting an execution
context. Though it makes no difference for this "problem" (can't stress
that enough), it is very useful to know this.

So if you see code that sets multiple styles and it calls a function to
set a single style in a loop (sound familiar?), you can figure on at
least one and maybe n re-flows during that loop. I see these patterns
all the time and adjusting them out usually leads to huge performance
increases (with very little effort invested), particularly for large and
complex DOM's (the norm, of course).

Jorge

unread,
Jan 13, 2010, 3:59:12 AM1/13/10
to
On Jan 13, 9:40 am, David Mark <dmark.cins...@gmail.com> wrote:
> (...)

> It's a simple click listener that needs to prevent re-entry in some
> cases. (...)

Mine not only does, but in addition warrants a redraw between sorts
(e.g. if the user clicked on a second column while the previous sort
was still running).
--
Jorge.

David Mark

unread,
Jan 13, 2010, 4:07:47 AM1/13/10
to

Not only does what?! And "warrants a redraw?" What do any of your
posts mean?

Jorge

unread,
Jan 13, 2010, 4:35:10 AM1/13/10
to
On Jan 13, 10:07 am, David Mark <dmark.cins...@gmail.com> wrote:
>
> Not only does what?!  And "warrants a redraw?"  What do any of your
> posts mean?

Too much thinking for you today... :-)
--
Jorge.

David Mark

unread,
Jan 13, 2010, 4:38:21 AM1/13/10
to

No, too much time reading your ludicrous one-liners. :(

Hans-Georg Michna

unread,
Jan 13, 2010, 4:52:42 AM1/13/10
to
On Wed, 13 Jan 2010 03:46:42 -0500, David Mark wrote:

>Hans-Georg Michna wrote:

>> Most browsers don't even render to screen, as long as any
>> JavaScript task is running, with the exception of Opera.

>That's incorrect. They virtually all re-flow on exiting an execution
>context. Though it makes no difference for this "problem" (can't stress
>that enough), it is very useful to know this.
>
>So if you see code that sets multiple styles and it calls a function to
>set a single style in a loop (sound familiar?), you can figure on at
>least one and maybe n re-flows during that loop. I see these patterns
>all the time and adjusting them out usually leads to huge performance
>increases (with very little effort invested), particularly for large and
>complex DOM's (the norm, of course).

You are saying that most browsers re-render to screen while some
JavaScript code is still to be or being executed? I haven't seen
that. What I see is that the browsers, except perhaps Opera,
don't do anything at all on screen until the JavaScript code
finishes execution or is killed because it ran for too long.

But I haven't done any exhausting tests on this. Has anybody
else here tested this thoroughly?

Hans-Georg

Jorge

unread,
Jan 13, 2010, 4:59:30 AM1/13/10
to
On Jan 13, 10:52 am, Hans-Georg Michna <hans-

A reflow is not a redraw. There's (usually) many (more) reflows per
redraw. Reflows happen during normal JS execution, but redraws
(exception: Opera) don't.
--
Jorge.

David Mark

unread,
Jan 13, 2010, 5:06:29 AM1/13/10
to
Hans-Georg Michna wrote:
> On Wed, 13 Jan 2010 03:46:42 -0500, David Mark wrote:
>
>> Hans-Georg Michna wrote:
>
>>> Most browsers don't even render to screen, as long as any
>>> JavaScript task is running, with the exception of Opera.
>
>> That's incorrect. They virtually all re-flow on exiting an execution
>> context. Though it makes no difference for this "problem" (can't stress
>> that enough), it is very useful to know this.
>>
>> So if you see code that sets multiple styles and it calls a function to
>> set a single style in a loop (sound familiar?), you can figure on at
>> least one and maybe n re-flows during that loop. I see these patterns
>> all the time and adjusting them out usually leads to huge performance
>> increases (with very little effort invested), particularly for large and
>> complex DOM's (the norm, of course).
>
> You are saying that most browsers re-render to screen while some
> JavaScript code is still to be or being executed?

What I said was they re-render on exiting execution contexts. So sure
there can still be JS to execute at that point.

> I haven't seen
> that.

Look again. :)

> What I see is that the browsers, except perhaps Opera,
> don't do anything at all on screen until the JavaScript code
> finishes execution or is killed because it ran for too long.

I don't know what you think you see in Opera, but I can tell you for
sure that it is not special in this regard. And your observations are
incorrect.

>
> But I haven't done any exhausting tests on this. Has anybody
> else here tested this thoroughly?
>

There's no need to do any tests on it. It's a documented fact. It's
something you must deal with when designing UI widgets that run in
browsers. If you don't know how re-flows work, you can't hope to write
efficient (or consistent) widgets. It's been roughly the same game
since IE4. The problem is that there is a tsunami of bad examples and
associated misinformation out there on the Web, while most of the good
stuff runs behind corporate firewalls (side by side with lots more crap
of course).

Looking for unnecessary re-flows and memory leak patterns is usually the
first thing I am asked to do on a project. Most people know there are
problems in those areas that affect performance and/or waste resources,
but they don't know exactly what the problem is. ;)

But the OP's "problem" has nothing to do with any of this. That one
falls under too much execution in a listener (another common gaffe).
Break it up into steps with timeouts and never mind when the re-flows
happen.

David Mark

unread,
Jan 13, 2010, 5:08:15 AM1/13/10
to

For seemingly the millionth time, re-flows happen on exiting execution
contexts (in virtually every known graphical browser).

but redraws
> (exception: Opera) don't.

You are out of your tiny little mind. :)

Jorge

unread,
Jan 13, 2010, 5:15:54 AM1/13/10
to
On Jan 13, 11:08 am, David Mark <dmark.cins...@gmail.com> wrote:
> (...)

> For seemingly the millionth time, re-flows happen on exiting execution
> contexts (in virtually every known graphical browser).

No. Reflows happen as needed. E.g. simply reading an .offsetWidth can
trigger a reflow.
--
Jorge.

Jorge

unread,
Jan 13, 2010, 5:31:04 AM1/13/10
to
On Jan 13, 11:15 am, Jorge <jo...@jorgechamorro.com> wrote:
>
> No. Reflows happen as needed. E.g. simply reading an .offsetWidth can
> trigger a reflow.

And 5 lines later, in the very same piece of code, reading it again
might trigger yet another reflow.
--
Jorge.

David Mark

unread,
Jan 13, 2010, 5:32:09 AM1/13/10
to

I don't any of these are standard terms. I've always used reflow (or
re-render) to refer to all of the expensive behind-the-scenes crap that
goes into updating the rendering (and can lead to unwanted peek-a-boo
behavior and/or performance drags).

So no, just getting the offsetWidth will not update the rendering.
Obviously it will _recalculate_ the offset width of that element, which
may entail considering queued rendering changes.

Exiting an execution context after mutating the DOM will update the
rendering (in some cases, it depends on numerous factors). But the
rendering is never updated during an execution context (even in Opera).
That's all you really need to know. I see people are no writing tools
to try to observe and analyze all of this stuff. I imagine they'll be
just as insightful as the leak detectors were.

David Mark

unread,
Jan 13, 2010, 5:33:06 AM1/13/10
to

Another _recalculation_ of the offsetWidth, but only if something
changed in between. So what?

Jorge

unread,
Jan 13, 2010, 5:36:31 AM1/13/10
to

You ought to watch this, from beginning to end:
"Faster HTML and CSS: Layout Engine Internals for Web Developers"
http://www.youtube.com/watch?v=a2_6bGNZ7bA
--
Jorge.

David Mark

unread,
Jan 13, 2010, 5:41:30 AM1/13/10
to
Jorge wrote:
> On Jan 13, 11:33 am, David Mark <dmark.cins...@gmail.com> wrote:
>> Jorge wrote:
>>> On Jan 13, 11:15 am, Jorge <jo...@jorgechamorro.com> wrote:
>>>> No. Reflows happen as needed. E.g. simply reading an .offsetWidth can
>>>> trigger a reflow.
>>> And 5 lines later, in the very same piece of code, reading it again
>>> might trigger yet another reflow.
>> Another _recalculation_ of the offsetWidth, but only if something
>> changed in between. So what?
>
> You ought to watch this, from beginning to end:
> "Faster HTML and CSS: Layout Engine Internals for Web Developers"
> http://www.youtube.com/watch?v=a2_6bGNZ7bA

Don't be an idiot. Somebody generalizing about how to write efficient
"Web 2.0" apps (or whatever?) Why would that interest me roughly
fourteen years later? This stuff is not new, Jorge. People can make up
new names for it, but it's still the same old shit and most of it is
common sense.

Jorge

unread,
Jan 13, 2010, 5:53:51 AM1/13/10
to
On Jan 13, 11:41 am, David Mark <dmark.cins...@gmail.com> wrote:
> (...) Somebody generalizing about how to write efficient
> "Web 2.0" apps (or whatever?) (..)

Yeah, sure. Obviously you have not seen it yet. But you should.
--
Jorge.

David Mark

unread,
Jan 13, 2010, 6:07:20 AM1/13/10
to

No I shouldn't, but thanks for thinking of me.

Stefan Mueller

unread,
Jan 14, 2010, 3:54:22 AM1/14/10
to
On Jan 13, 3:12 am, Jorge <jo...@jorgechamorro.com> wrote:
> Stefan,
>
> All you need to do is to wrap the whole thing in a setTimeout
> (sortingCode ,0); That will warrant a redraw *before* it executes.
> Like this:
>
> elem.onclick= function onclick () {
>   elem.onclick= null; //trash useless double-clicks
>   setTimeout(function () {
>
>     //Put your sorting code here.
>
>     elem.onclick= onclick;
>   }, 0);};
>
> --
> Jorge.

Jorge,

I tried to implement setTimeout but I'm not sure if I did it correct
(the way you advised me to do):
var_this_global = this;
var_todo_global = "function_sort(var_this_global);";
setTimeout(var_todo_global, 1200);

It only works if I set the value in setTimeout to at least 1200. It
works if you click a second time on a column header while the sorting
is running. But it doesn't work if you click a third time.
Because I have to set the value to at least 1200 it always takes 1.2
seconds until the sorting starts.

Stefan

David Mark

unread,
Jan 14, 2010, 4:01:12 AM1/14/10
to
Stefan Mueller wrote:
> On Jan 13, 3:12 am, Jorge <jo...@jorgechamorro.com> wrote:
>> Stefan,
>>
>> All you need to do is to wrap the whole thing in a setTimeout
>> (sortingCode ,0); That will warrant a redraw *before* it executes.
>> Like this:
>>
>> elem.onclick= function onclick () {
>> elem.onclick= null; //trash useless double-clicks
>> setTimeout(function () {
>>
>> //Put your sorting code here.
>>
>> elem.onclick= onclick;
>> }, 0);};
>>
>> --
>> Jorge.
>
> Jorge,
>
> I tried to implement setTimeout but I'm not sure if I did it correct
> (the way you advised me to do):

That's assuming Jorge advised you correctly (usually a stretch). As I
mentioned, you don't really have a problem. If your process takes too
long (and it definitely does), you need to break it up. Then the clicks
(or whatever user actions) will not be "cached" while the engine is
waiting for your sort to finish. Solve the real problem and the
imagined one will go away. ;)

> var_this_global = this;
> var_todo_global = "function_sort(var_this_global);";
> setTimeout(var_todo_global, 1200);
>
> It only works if I set the value in setTimeout to at least 1200. It
> works if you click a second time on a column header while the sorting
> is running. But it doesn't work if you click a third time.
> Because I have to set the value to at least 1200 it always takes 1.2
> seconds until the sorting starts.
>

You are wasting your time. Do what I told you to do. You can't go
wrong that way.

Jorge

unread,
Jan 14, 2010, 10:38:14 AM1/14/10
to

Ok. check this one:
http://jorgechamorro.com/cljs/092/

Does it work for you ?
--
Jorge.

Hans-Georg Michna

unread,
Jan 14, 2010, 6:09:54 PM1/14/10
to
By the way, how do you sort? Do you use JavaScript's array sort
function? If not, you probably should, for higher speed.

Hans-Georg

kangax

unread,
Jan 16, 2010, 2:51:42 AM1/16/10
to
On 1/13/10 5:32 AM, David Mark wrote:
> Jorge wrote:
>> On Jan 13, 11:08 am, David Mark<dmark.cins...@gmail.com> wrote:
>>> (...)
>>> For seemingly the millionth time, re-flows happen on exiting execution
>>> contexts (in virtually every known graphical browser).
>>
>> No. Reflows happen as needed. E.g. simply reading an .offsetWidth can
>> trigger a reflow.
>
> I don't any of these are standard terms. I've always used reflow (or
> re-render) to refer to all of the expensive behind-the-scenes crap that
> goes into updating the rendering (and can lead to unwanted peek-a-boo
> behavior and/or performance drags).

Browsers differ, but there's usually a _reflow_ and there's a _repaint_.
Reflow is when render tree is recalculated; repaint � when screen is
updated.

>
> So no, just getting the offsetWidth will not update the rendering.
> Obviously it will _recalculate_ the offset width of that element, which
> may entail considering queued rendering changes.

Querying `offsetWidth` does trigger _reflow_. Obviously, all queued
changes need to be applied before returning value.

>
> Exiting an execution context after mutating the DOM will update the
> rendering (in some cases, it depends on numerous factors). But the
> rendering is never updated during an execution context (even in Opera).
> That's all you really need to know. I see people are no writing tools
> to try to observe and analyze all of this stuff. I imagine they'll be
> just as insightful as the leak detectors were.

Tools are actually quite useful. Do you know that IE reflows when
changing, say, color (!) style of an element (whereas Chrome, for
example, doesn't). Do you know that IE reflows even when changing style
of "display:none" element?

You might also be interested in:

<http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/>
<http://www.phpied.com/the-new-game-show-will-it-reflow/>

and some overview of Mozilla internals:

<https://developer.mozilla.org/En/Introduction_to_Layout_in_Mozilla>


--
kangax

Hans-Georg Michna

unread,
Jan 16, 2010, 6:48:21 AM1/16/10
to
On Sat, 16 Jan 2010 02:51:42 -0500, kangax wrote:

I have some doubt here. The author writes under "Minimizing
repaints and reflows", referring to DOM modifications through
JavaScript:

"• Don't change individual styles, one by one. …"

But that looks like nonsense, as the browser will surely not
reflow the document while the JavaScript code is still running,
at least not while the same JavaScript function is still
running.

In fact, wouldn't it be wise for the browser to wait until all
JavaScript processing has finished and the processor has nothing
better to do?

Hans-Georg

Jorge

unread,
Jan 16, 2010, 7:21:51 AM1/16/10
to
On Jan 16, 12:48 pm, Hans-Georg Michna <hans-

reflow !== redraw (!)

Say you've got:

element.style.color= "red";
var height= element.offsetHeight; //won't reflow (except in IE :-))

But:
element.style.fontSize= (a different value);
var height= element.offsetHeight; //requires a reflow
--
Jorge.

kangax

unread,
Jan 16, 2010, 11:43:10 AM1/16/10
to
On 1/16/10 6:48 AM, Hans-Georg Michna wrote:
> On Sat, 16 Jan 2010 02:51:42 -0500, kangax wrote:
>
>> You might also be interested in:
>>
>> <http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/>
>
> I have some doubt here. The author writes under "Minimizing
> repaints and reflows", referring to DOM modifications through
> JavaScript:
>
> "• Don't change individual styles, one by one. …"
>
> But that looks like nonsense, as the browser will surely not
> reflow the document while the JavaScript code is still running,
> at least not while the same JavaScript function is still
> running.

So if element dimensions change while function is running, what do you
expect to see when inspecting that element's dimensions? Same value?

For example:

(function(){

var offsets = [];

for (var i = 100; i <= 500; i += 100) {
document.body.style.width = i + 'px';
offsets.push(document.body.offsetWidth);
}

return offsets;

})();

Should `offsets` now contain same values?

>
> In fact, wouldn't it be wise for the browser to wait until all
> JavaScript processing has finished and the processor has nothing
> better to do?

For repaint, sure, but not for reflow.

--
kangax

Jorge

unread,
Jan 16, 2010, 12:03:35 PM1/16/10
to

Opera does -under certain circumstances- *redraw* in a separate
thread, in parallel with JS execution. That's wiser imo, but a
window.redraw() DOM method would be even wiser yet :-)
--
Jorge.

Garrett Smith

unread,
Jan 16, 2010, 6:00:23 PM1/16/10
to

The author of that article makes several claims, but does not state the
basis for any of them.

What the author considers to be triggering reflow applies to recent
popular browsers. Some of it is incorrect for Safari 2, slightly older
versions of Gecko (1.8), and Blackberry9000.

The author says reflow happens "when you request style information such
as" and the list that follows includes `currentStyle`.

I do not know how the author arrived at that conclusion. I cannot see
why it is necessary for IE to recalc when currentStyle is accessed.

MSDN on cascaded style state:-
| Represents the cascaded format and style of the object as specified by
| global style sheets, inline styles, and HTML attributes.

But then he doesn't bother explaining that before moving onto a
solution: createDocumentFragment. The author states that appending to
content within a documentFragment won't cause a reflow. Sounds pretty
obvious, but the focus on documentFragment is misleading; there's
nothing magic about documentFragment.

The key fact that the author misses is that the documentFragment is not
in the DOM. The key *principle* to avoid (and this is nothing new,
folks), is to perform all the node creation/appending before adding to
the DOM.

> <http://www.phpied.com/the-new-game-show-will-it-reflow/>
>

| Will the browser reflow when you update stylesheet collections
| programatically? Here's the test case using addRule and removeRule
| (which in Firefox are insertRule/deleteRule):

That's misleading. addRule is a method of an IE stylesheet; part of IE
DOM. insertRule is the standard method, not the Firefox method.

That blog entry seems to have some missing semicolons.


The dynaTrace blog that he links to states:-
In "Rendering triggered by Property Read Access", the author does not
define clearly what he means by "read access". Instead he uses jQuery
height() method.
http://blog.dynatrace.com/2009/12/12/understanding-internet-explorer-rendering-behaviour/

The graphic depicted on that blog seems to indicate that dynaTrace found
a repaint after `isXMLDoc`, which is called by attr.

Is there something valuable or informative anywhere there?

> and some overview of Mozilla internals:
>
> <https://developer.mozilla.org/En/Introduction_to_Layout_in_Mozilla>
>

Good link.
--
Garrett
comp.lang.javascript FAQ: http://jibbering.com/faq/

Hans-Georg Michna

unread,
Jan 17, 2010, 5:58:23 AM1/17/10
to
On Sat, 16 Jan 2010 04:21:51 -0800 (PST), Jorge wrote:

>But:
>element.style.fontSize= (a different value);
>var height= element.offsetHeight; //requires a reflow

Sure, but the question is, when is the reflow required and when
does it actually happen?

The sensible thing to do for the browser is nothing, while the
running JavaScript code may be adding more DOM changes, then do
one reflow in the end.

Hans-Georg

Hans-Georg Michna

unread,
Jan 17, 2010, 5:58:23 AM1/17/10
to
On Sat, 16 Jan 2010 11:43:10 -0500, kangax wrote:

>So if element dimensions change while function is running, what do you
>expect to see when inspecting that element's dimensions? Same value?
>
>For example:
>
>(function(){
>
> var offsets = [];
>
> for (var i = 100; i <= 500; i += 100) {
> document.body.style.width = i + 'px';
> offsets.push(document.body.offsetWidth);
> }
>
> return offsets;
>
>})();
>
>Should `offsets` now contain same values?

>> In fact, wouldn't it be wise for the browser to wait until all
>> JavaScript processing has finished and the processor has nothing
>> better to do?

>For repaint, sure, but not for reflow.

You are right, but only if a reflow result is actually queried
by the JavaScript code. As long as that doesn't happen, a reflow
is not needed.

I see that I have to change my statement. A reflow should not
happen while JavaScript code is running, with the exception that
the JavaScript code queries anything that depends on a reflow.

Since it is known which parameters depend on a reflow and which
don't, that shouldn't be difficult to implement.

The simple description of this method would be, "Reflow only as
needed."

Hans-Georg

kangax

unread,
Jan 17, 2010, 8:57:48 AM1/17/10
to
On 1/17/10 5:58 AM, Hans-Georg Michna wrote:
> On Sat, 16 Jan 2010 11:43:10 -0500, kangax wrote:
>
>> So if element dimensions change while function is running, what do you
>> expect to see when inspecting that element's dimensions? Same value?
>>
>> For example:
>>
>> (function(){
>>
>> var offsets = [];
>>
>> for (var i = 100; i<= 500; i += 100) {
>> document.body.style.width = i + 'px';
>> offsets.push(document.body.offsetWidth);
>> }
>>
>> return offsets;
>>
>> })();
>>
>> Should `offsets` now contain same values?
>
>>> In fact, wouldn't it be wise for the browser to wait until all
>>> JavaScript processing has finished and the processor has nothing
>>> better to do?
>
>> For repaint, sure, but not for reflow.
>
> You are right, but only if a reflow result is actually queried
> by the JavaScript code. As long as that doesn't happen, a reflow
> is not needed.

Yep.

>
> I see that I have to change my statement. A reflow should not
> happen while JavaScript code is running, with the exception that
> the JavaScript code queries anything that depends on a reflow.

Of course. In fact, that's exactly what (modern) Gecko and WebKit do.

To quote one of Zbarsky's (senior engineer at Mozilla) replies in a
WHATWG thread
(<http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2009-September/023209.html>):

"Note that Gecko will not perform layout while your script is running,
unless you ask for layout information."

[...]

--
kangax

Jorge

unread,
Jan 17, 2010, 12:38:44 PM1/17/10
to
On Jan 17, 11:58 am, Hans-Georg Michna <hans-

georgNoEmailPle...@michna.com> wrote:
> On Sat, 16 Jan 2010 04:21:51 -0800 (PST), Jorge wrote:
> >But:
> >element.style.fontSize= (a different value);
> >var height= element.offsetHeight; //requires a reflow
>
> Sure, but the question is, when is the reflow required and when
> does it actually happen?

Reflows happen as needed: either because your code is asking for data
that requires (and triggers) it, or because it's time for a reDRAW.

> The sensible thing to do for the browser is nothing, while the
> running JavaScript code may be adding more DOM changes, then do
> one reflow in the end.

...unless your code asks for some data that triggers it.

Even if reflows are known to be expensive operations, simply asking
for an .offsetXXX seems to be very expensive too, even when it should
*not* trigger a reflow. At least that's what it looks like in this
test:

http://jorgechamorro.com/cljs/094/

The relative speeds I see (in a Mac) are:

Reflow needed read .offsetXXX speed S O C FF
Don't care NO 100% 100% 100% 100%
NO YES 10% 25% 32% 42%
YES YES 1.4% 2.8% 3.9% 9.5%
--
Jorge.

Stefan Mueller

unread,
Jan 18, 2010, 4:36:26 AM1/18/10
to

Jorge,

At the weekend I've done quite a lot of testing with your code and yes
your code works perfect!
Many thanks for your great help.

Stefan

Stefan Mueller

unread,
Jan 18, 2010, 4:37:14 AM1/18/10
to
On Jan 15, 12:09 am, Hans-Georg Michna <hans-

I'm not using the JavaScript's array sort function because I want to
add additional features (empty rows should always be at the end /
already sorted columns should not get mixed up while another column
gets sorted / ...).
Anyway, thanks for the hint.

Stefan

Jorge

unread,
Jan 18, 2010, 6:32:29 AM1/18/10
to
On Jan 18, 10:36 am, Stefan Mueller <seekw...@yahoo.com> wrote:
>
> Jorge,
>
> At the weekend I've done quite a lot of testing with your code and yes
> your code works perfect!
> Many thanks for your great help.

You're welcome.
--
Jorge.

Hans-Georg Michna

unread,
Jan 18, 2010, 12:47:45 PM1/18/10
to
Thanks, all. I've learned something again.

Hans-Georg

kangax

unread,
Jan 18, 2010, 10:29:05 PM1/18/10
to

What is it exactly that doesn't trigger reflow in Safari 2, older Gecko
and Blackberry? And how do you know that it doesn't?

>
> The author says reflow happens "when you request style information such
> as" and the list that follows includes `currentStyle`.
>
> I do not know how the author arrived at that conclusion. I cannot see
> why it is necessary for IE to recalc when currentStyle is accessed.

I see his arrival to such conclusion right after list itself:

"All of these above are essentially requesting style information about a
node, and any time you do it, the browser has to give you the most
up-to-date value. In order to do so, it needs to apply all scheduled
changes, flush the queue, bite the bullet and do the reflow."

>
> MSDN on cascaded style state:-
> | Represents the cascaded format and style of the object as specified by
> | global style sheets, inline styles, and HTML attributes.
>
> But then he doesn't bother explaining that before moving onto a
> solution: createDocumentFragment. The author states that appending to
> content within a documentFragment won't cause a reflow. Sounds pretty
> obvious, but the focus on documentFragment is misleading; there's
> nothing magic about documentFragment.
>
> The key fact that the author misses is that the documentFragment is not
> in the DOM. The key *principle* to avoid (and this is nothing new,
> folks), is to perform all the node creation/appending before adding to
> the DOM.

Yes.

>
>> <http://www.phpied.com/the-new-game-show-will-it-reflow/>
>>
>
> | Will the browser reflow when you update stylesheet collections
> | programatically? Here's the test case using addRule and removeRule
> | (which in Firefox are insertRule/deleteRule):
>
> That's misleading. addRule is a method of an IE stylesheet; part of IE
> DOM. insertRule is the standard method, not the Firefox method.

You're nitpicking :) He didn't say that `insertRule` is Firefox's
method. He said that in Firefox there's `insertRule`. I could also say
that there's `insertRule` in Safari, and that wouldn't be wrong. It
would be just incomplete and somewhat unprofessional.

I also noticed that some tests are in quirks mode
(<http://www.phpied.com/files/reflow/restyle.html>), which is not a good
idea.

>
> That blog entry seems to have some missing semicolons.
>
>
> The dynaTrace blog that he links to states:-
> In "Rendering triggered by Property Read Access", the author does not
> define clearly what he means by "read access". Instead he uses jQuery
> height() method.
> http://blog.dynatrace.com/2009/12/12/understanding-internet-explorer-rendering-behaviour/

I was annoyed by that too. Was it `offsetHeight`?

dynaTrace is freely available, so anyone can check reflow behavior in IE.

[...]

--
kangax

Garrett Smith

unread,
Jan 19, 2010, 1:19:17 AM1/19/10
to

Reading width property failed me before.

There was an element in the page directly followed by a script that was
trying to read offsetWidth and it was getting the wrong value.

>>
>> The author says reflow happens "when you request style information such
>> as" and the list that follows includes `currentStyle`.
>>
>> I do not know how the author arrived at that conclusion. I cannot see
>> why it is necessary for IE to recalc when currentStyle is accessed.
>
> I see his arrival to such conclusion right after list itself:
>
> "All of these above are essentially requesting style information about a
> node, and any time you do it, the browser has to give you the most
> up-to-date value. In order to do so, it needs to apply all scheduled
> changes, flush the queue, bite the bullet and do the reflow."
>

currentStyle is a cascaded style. What queue needs to be flushed?

>>
>> MSDN on cascaded style state:-

MSDN on *currentStyle*:-


>> | Represents the cascaded format and style of the object as specified by
>> | global style sheets, inline styles, and HTML attributes.
>>
>> But then he doesn't bother explaining that before moving onto a
>> solution: createDocumentFragment. The author states that appending to
>> content within a documentFragment won't cause a reflow. Sounds pretty
>> obvious, but the focus on documentFragment is misleading; there's
>> nothing magic about documentFragment.
>>
>> The key fact that the author misses is that the documentFragment is not
>> in the DOM. The key *principle* to avoid (and this is nothing new,
>> folks), is to perform all the node creation/appending before adding to
>> the DOM.
>
> Yes.
>
>>
>>> <http://www.phpied.com/the-new-game-show-will-it-reflow/>
>>>
>>
>> | Will the browser reflow when you update stylesheet collections
>> | programatically? Here's the test case using addRule and removeRule
>> | (which in Firefox are insertRule/deleteRule):
>>
>> That's misleading. addRule is a method of an IE stylesheet; part of IE
>> DOM. insertRule is the standard method, not the Firefox method.
>
> You're nitpicking :) He didn't say that `insertRule` is Firefox's
> method. He said that in Firefox there's `insertRule`. I could also say
> that there's `insertRule` in Safari, and that wouldn't be wrong. It
> would be just incomplete and somewhat unprofessional.
>

There isn't any good reason for preferring the non-standard addRule
method over the standard one. The quirks that come with IE dhtml methods
are not always copied the same in other browsers.

With standard method, there is a specification that is clearer then MSDN
and doesn't have all the associated quirks copied over.

> I also noticed that some tests are in quirks mode
> (<http://www.phpied.com/files/reflow/restyle.html>), which is not a good
> idea.
>

Right, not a good idea.

>>
>> That blog entry seems to have some missing semicolons.
>>
>>
>> The dynaTrace blog that he links to states:-
>> In "Rendering triggered by Property Read Access", the author does not
>> define clearly what he means by "read access". Instead he uses jQuery
>> height() method.
>> http://blog.dynatrace.com/2009/12/12/understanding-internet-explorer-rendering-behaviour/
>>
>
> I was annoyed by that too. Was it `offsetHeight`?
>

The tool vendor seems to be referring to jQuery `height` method.

#upper:
`isXMLDoc` is called, then "Rendering (Scheduling layout task #47)".

#lower:
`css` is called, then "Rendering (Scheduling layout task #47)"

| Why does this happen, especially as the property change on the upper
| div element has no effect on the lower div element? When the height
| property of the lower div element is accessed Internet Explorer
| realizes that there is a scheduled layouting task.

Accessing the `height` property of the `jQuery.prototype.init` object
should not require layout update.

The paragraph continues:-

| As this task might � and most likely will � change layout properties
| of other elements it is performed before layouting-related information
| is returned by the DOM call.

Calling the `height` property of the `jQuery.prototype.init` object
should not require layout update.

I should clarify that. The constructor for a jQuery object is the init
function, which is in the prototype property of the jQuery function. The
jQuery constructor is in the prototype, as jQuery.prototype.init.

Any object created by jQuery is an instance of jQuery.prototype.init.
For example, using jQuery:

$() instanceof jQuery.prototype.init;

true

Kind of an odd design, but that is beside the point.

The calling a jQuery.init's `height` property is a not DOM update. There
is no reason that it should require layout update.

When the tool vendor called `height`, the tool displayed rendering
scheduling notification in two cases:

#upper:
`isXMLDoc` is called, then "Rendering (Scheduling layout task #47)".

#lower:
`css` is called, then "Rendering (Scheduling layout task #47)"

Did I miss learning something?

0 new messages