From: Thomas 'PointedEars' Lahn on
Jorge wrote:

> Thomas 'PointedEars' Lahn wrote:
>> Jorge wrote:
>> > Thomas 'PointedEars' Lahn wrote:
>> >> Jorge wrote:
>> >> > Thomas 'PointedEars' Lahn wrote:
>> >> >> <http://pointedears.de/scripts/test/dom/events/window-onload.mpeg>
>> >> >>
>> >> >> Will you *please* shut up now?
>> >> >
>> >> > Why ?
>> >> > He's right.
>> >> > The page in your video is not drawn until after window.onload
>> >> > returns:
>> >>
>> >> That is
>> >>
>> >> 1. not what he stated:
>> >>
>> >> | They mean KEEP THE SCREEN BLANK until the script executed, apply DOM
>> >> | changes if any, and only then display the page for the first time.
>> >>
>> >> and 2. not what happens. The heading is there, and "the page
>> >> displayed for the first time" long before. No "blank screen"
>> >> whatsoever.
>> >
>> > Well, I get the blank screen for 20s in Safari, Chrome, FF 2..3.6,
>> > NSNavigator, Flock and iCab, but not in Operas nor in IE5.2.3, on Mac
>> > OSX.
>>
>> Apparently you don't know what "blank" and "first time" mean.
>
> FYI: a blank screen means that the heading is not there, that nothing
> is there but a blank, empty page, for 20 seconds.

In Firefox 3.6? I can only assume in your favor that you did not use the
code in VK's posting, or that you used a different Gecko version than me
(rv:1.9.2.3, Gecko/20100404), as my video shows the what happens when using
that code in Iceweasel 3.6.3, which is basically Firefox 3.6.3 for Debian
GNU/Linux. And no, it is the original package.

Anyhow, the fact that iff you tested with the same code and Gecko version as
me, and the result here would still be evidently different, should teach you
a lesson about knee-jerk generalizations.

>> >> > replace your window.onload with this one in order to see:
>> >> >
>> >> > window.onload= function (now) {
>> >> > now= +new Date()+ 20e3;
>> >> > while(+new Date() < now) {}
>> >> > init();
>> >> > };
>> >>
>> >> That does not prove his knee-jerk generalization either. It only
>> >> proves that time-consuming tasks like those slow down loading of the
>> >> document. What else is new?
>> >
>> > The document is fully loaded when onload fires, remember, that's the
>> > whole point of the onload event.
>>
>> There is no "onload event", and you miss the point. "Loaded" does not
>> need to mean "rendered", and in fact it is well-known that the `load'
>> event may occur well before all content has been fully rendered (images,
>> for example).
>
> And well before *any* content is rendered, it seems.

It is entirely possible if a time-consuming operation takes precedence.
Another possibility is that nodes are directly inserted into the document
tree, so that a concurrent reflow would be triggered while the document is
still being rendered. That is the very point. Knee-jerk generalizations
are unjustified.

>> >> But assuming the generalization would be true, how do you explain
>> >> <http://PointedEars.de/es-matrix/index-alert>, where the console
>> >> message and the alert message box is displayed *after* the table of
>> >> contents is displayed (at least in Iceweasel 3.6.3)?
>> >
>> > That page is too complicated for me to dig in it. Could you please
>> > post a shorter example to prove your point ?
>>
>> No. The very point of this is that it is a considerably large document
>> (a slightly adapted copy of the original Matrix) which makes it a much
>> better test case for any possible timing issues with the `load' event
>> than the short one which was posted by VK here (not to mention that the
>> window.setTimeout() call only complicates the issue in a
>> *single-threaded* environment).
>>
>> You only need to recognize that and look for the window.alert() call in
>> the `onload' attribute of the `body' element's start tag. And observe
>> the document content being displayed well before the alert message.
>
> Maybe. But you should not call alert() as it adds an additional
> variable to the equation.

No. It tests exactly VK's assumption, and your assumption, that content
would not ever be displayed before the `load' listener returned. Do you
deny that they wrote:

| window.onload / body onload= / addEventListener('load',..
| do not mean "display the page and start the script execution"
|
| They mean KEEP THE SCREEN BLANK until the script executed, apply DOM
| changes if any, and only then display the page for the first time.

and that you wrote:

| The page in your video is not drawn until after window.onload returns:

?

> It might very well be -and it would really make a lot of sense- that all
> browsers redraw the screen before an alert,

I don't see why.

> but that would have nothing to do with what VK was saying.

ISTM you have either not read or completely misunderstood what they were
saying. Then again, there is a good chance that they themselves have not
understood what they were saying, so ...

>> We know with considerable certainty that window.alert() holds script
>> execution until after the alert message was confirmed.
>
> True. But your attempt at cheating now by introducing an alert() is
> quite lame, really.

The pot calling the kettle black.

>> If VK's knee-jerk generalization would be true we should be seeing no
>> document content whatsoever until after the alert message was confirmed.
>
> No. Not really.

Yes. Undoubtedly.

> As there was no alert() in his code.

That is the problem! Time-consuming tree-manipulating code was used instead
-- facts being twisted to suit theories.

>> But obviously that is _not_ the case. Logic dictates that if the set
>> union of assumption and facts is inconsistent (i.e. contradictory), the
>> assumption must be false. q.e.d.
>
> QED or whatever,

That is Latin for "that which was to be demonstrated" (it is written in all-
lowercase in German).

<http://en.wikipedia.org/wiki/Q.E.D.>

> his code yields a blank page in 6 out of 8 browsers.

Perhaps with you. But you misunderstand why, and you fail to see the
significance of the *6* out of 8 when, following VK's generalization, it
should have been *8* out of 8.


PointedEars
--
Use any version of Microsoft Frontpage to create your site.
(This won't prevent people from viewing your source, but no one
will want to steal it.)
-- from <http://www.vortex-webdesign.com/help/hidesource.htm> (404-comp.)
From: Stefan Weiss on
On 18/04/10 19:32, Johannes Baagoe wrote:
> Jorge :
>> Johannes Baagoe :
>
>>> I shall therefore continue to misuse setTimeouts. I hoped there
>>> would be a better way, but apparently, there is not.
>
>> You're right: there's no better way. Currently only Opera renders DOM
>> changes to the screen in parallel with JS execution (in a separate
>> thread, or process, or whatever). I agree with you that something
>> along the lines of a ~ window.renderNow() would be a Good Thing™,
>> and it wouldn't "break the web".

There is a (rather hackish) way to encourage some browsers to do an
immediate redraw, even in the middle of a running script. I've never
needed this myself, but the question looked interesting, and what I came
up with appears to work in FF 3.0 and MSIE 6+7; Opera didn't behave as
nicely. I haven't tested any other browsers, and I wouldn't expect it to
work everywhere.

What it comes down to is letting some element on the page scroll by
setting its scrollTop or scollLeft properties. That's probably even
worse than "abusing" setTimeout, and it hurts the script's overall
performance, but since you wanted a forced redraw, and the only answer
was "can't be done"... I've added an example at the end.

Personally, I wouldn't try to force redraws at all. I would break up a
long running calculation into steps, using setTimeout to connect them.
After each step, the intermediate results can be displayed on the page.
The basic structure could look like this (pseudo code):

function runCalculation (...) {

var state;

// (use arguments for initialization)
runStep(...);

function runStep (...) {
var stepResult = calculateStep(...);
displayOutput(stepResult);
if (more steps are required) {
window.setTimeout(resume, 10);
}
}

function resume () {
// (use 'state' var for preparation, if necessary)
runStep(...);
}

function calculateStep (...) {
// (do a single calculation step)
state = { intermediate results };
return stepResult;
}

function displayOutput (stepResult) {
// changes the DOM
}

}

> Failing that, the very minimum would be a standard and convenient
> function like `window.yield()`, meaning "Do whatever requires your
> attention, and come back when you have finished".

Note that "yield" is a keyword in JavaScript 1.7.


stefan




<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Redraw test #1</title>
<style type="text/css">
p {
width: 15em;
border: 1px solid black;
margin: 2px;
}
#scroller {
position: absolute;
top: 0;
left: 0;
height: 1px;
width: 1px;
overflow: scroll;
}
#scroller div {
height: 2px;
}
</style>
<script type="text/javascript">
function fillTargets () {
var targets = document.getElementsByTagName("p"),
numTargets = targets.length,
scroller = document.getElementById("scroller");
for (var i = 0; i < numTargets; ++i) {
targets[i].innerHTML = +new Date();
scroller.scrollTop++;
scroller.scrollTop--;
for (var now = +new Date(); +new Date() < now + 200;);
}
}
</script>
</head>
<body>
<p>-</p> <p>-</p> <p>-</p> <p>-</p>
<p>-</p> <p>-</p> <p>-</p> <p>-</p>
<div>
<button onclick="fillTargets()">Fill targets</button>
<div id="scroller"><div></div></div>
</div>
</body>
</html>
From: Johannes Baagoe on
Thomas 'PointedEars' Lahn :
> Johannes Baagoe :
>> Thomas 'PointedEars' Lahn :

>>> Why should I replace an element with its clone when I could simply
>>> modify its properties?

>> It seems the natural thing to do if one does not want the successive
>> modifications to cause the layout to be recalculated and the window
>> redrawn at each modification.

> No. Current DOM implementations have a long history, and there has
> not always been a cloneNode() method.

It has been there since REC-DOM-Level-1-19981001. What earlier DOM
implementations do you have in mind?

>> Now, if there is some authoritative standard, say, in the W3C DOM
>> specifications, which says that this is *not* what should happen, I
>> stand corrected - one may safely assume that on conforming browsers,
>> the changes will only cause recalculation when the functions that
>> makes them returns, or at some other moment the standard specifies.

>> Is there?

> JFTR, I don't know one, and IMNSHO it is not the purpose of W3C
> interface specifications to define implementation behavior in that
> great detail.

If the rules are silent, it seems to me that the prudent approach is
to assume the worst, and to code accordingly.

Which in this case means never update a visible DOM object unless
you are willing to risk it to be rendered immediately.

> But you know what, you are really funny. When a specified reference
> is being presented to you that recommends not to do something,
> you demand empirical evidence before you would reconsider your
> design decision.

Goodness! It was about replacing "<th/>" with "<th></th>".

Both, according to http://www.w3.org/TR/REC-xml/#NT-EmptyElemTag,
*may* be used, but the second *should* (not "shall") be used "for
interoperability".

Definition of "for interoperability" : "Marks a sentence describing
a non-binding recommendation included to increase the chances that
XML documents can be processed by the existing installed base of
SGML processors which predate the WebSGML Adaptations Annex to ISO
8879." (http://www.w3.org/TR/REC-xml/#dt-interop)

May I not decide that I don't really care about such "SGML processors"
on my own website, assuming that there still are some in existence?

Still, to end that argument, I have actually changed my "<th/>" on
the site. Do you wish me to add an acknowledgment for your kind
advice that made me do so? (Some of your *other* advices would
fully justify it.)

> And when there is empirical evidence that something works as described
> you demand a specification reference before you would reconsider
> your design decision.

Well, yes, I have never been much of a fan of trial and error. I
am surprised that you seem to rely on observed behaviour instead of
assuming the worst that could happen on a *conforming* platform.

> Make up your mind!

I have, long time ago: it all depends on the context.

> AISB, you don't know what you are talking about.

Possibly, I am here to learn, and I hadn't thought of animations. I
do know quite a bit about updating parts of a page in rather complex
ways, albeit in controlled environments with a specific browser,
and with more focus on XML databases than on visual effects.

But /ça tombe bien/, I need a few animations to demonstrate various
things about random number generators. I shall try both approaches,
and see what difference it makes.

--
Johannes
From: Johannes Baagoe on
Stefan Weiss :

> There is a (rather hackish) way to encourage some browsers to do an
> immediate redraw, even in the middle of a running script.

> What it comes down to is letting some element on the page scroll by
> setting its scrollTop or scollLeft properties. That's probably even
> worse than "abusing" setTimeout, and it hurts the script's overall
> performance, but since you wanted a forced redraw, and the only answer
> was "can't be done"... I've added an example at the end.

Yes, well, that is *much* too hackish for my taste, but I admire the
ingenuity.

> Personally, I wouldn't try to force redraws at all. I would break up a
> long running calculation into steps, using setTimeout to connect them.

That is what I ended up with doing, before asking the group if there
was a better way, and being told that there isn't.

I resent that application programmers have to do things like that,
it puts us back at least twenty years back in time to the bad days
of MacOS 7's "cooperative multitasking", and arguably more, since
real multitasking was well understood even then. One should be able
to simply write one's functions, no matter how lengthy, and leave it
to the system to interrupt periodically when it needs the processor.
(I don't run into the problem too often, since my lengthy functions
in javascript usually run in the console, and *that* is properly
interrupted by any decent modern OS, in my case Linux.)

> After each step, the intermediate results can be displayed on the page.
> The basic structure could look like this (pseudo code):

> function runCalculation (...) {
>
> var state;
>
> // (use arguments for initialization) runStep(...);
>
> function runStep (...) {
> var stepResult = calculateStep(...);
> displayOutput(stepResult);
> if (more steps are required) {
> window.setTimeout(resume, 10);
> }
> }
>
> function resume () {
> // (use 'state' var for preparation, if necessary)
> runStep(...);
> }
>
> function calculateStep (...) {
> // (do a single calculation step)
> state = { intermediate results };
> return stepResult;
> }
>
> function displayOutput (stepResult) {
> // changes the DOM
> }
>
> }

That seems to me to be about the cleanest one can do, things being what
they are. Thanks a lot.

> Note that "yield" is a keyword in JavaScript 1.7.

Aha, I hadn't noticed that. I am not sure whether it is good or bad
news, though.

--
Johannes
From: Johannes Baagoe on
Jorge:

> A second thought:

> The purpose of .yield() would be to service pending events while
> preserving (that is, avoiding the need to exit/destroy) the current
> execution context, right ?

Well, yes, one could look at it that way. I didn't spontaneously,
since I normally take it for granted that the context is not altered
by a function call, except for special cases where the function has
side effects, which I avoid whenever possible. `yield` is not supposed
to have side effect - at least, side effects that concern me, that is,
my execution context. Your way of putting it is quite enlightening.

> For example, this code:
>
> (function contextContainer () {
> var contextData;
>
> do {
> workOn(contextData);
> yield();
> } while (!done());
>
> })();

I see. What I had in mind was more basic, like

for (var i = 0; i < someLargeishNumber; i++) {
someJustAcceptablySlowFunction();
yield();
}

or even

someJustAcceptablySlowFunction();
yield();
anotherJustAcceptablySlowFunction();
yield();

etc.

> But, as JS functions carry their contexts with them (a closure),
> somehow it's not such a big deal, it requires not much effort -at
> least in JS- to exit a context and happily resume later, because
> the context is automatically saved for you:

> (function contextContainer () {
> var contextData;
>
> (function iCarryTheContext () {
> workOn(contextData);
> !done() && setTimeout(iCarryTheContext, 0);
> })();
>
> })();

I presume that should be (you seem to have dropped a part in a
copy/paste):

(function contextContainer () {
var contextData;

(function iCarryTheContext () {
do {
workOn(contextData);
} while (!done() && setTimeout(iCarryTheContext, 0));
})();

})();

setTimeout returns a timeoutID, if we may assume that it never
gets converted to false, like 0 or '', I understand.

Very cute! I'll have to think about whether it could actually improve
my code in the PRNG speed test page. Offhand, I would say no, not
really, it would make it less legible for no actual benefit, but I
will give it a try.

--
Johannes