Firefox 3.5.5 crapping itself (redux)

N

Nik Coughlin

I really am going mad here. Firefox is going really slowly on something that
should be trivial and is in fact very fast in all of my other browsers.

The strange thing is that for most people, it's not happening. It happens on
my machine here, and I've tried using Firefox with a clean profile, Firefox
Portable etc. with the same result. It does however happen for some people,
which is a concern.

Consider the following:

var targetForManyElements = document.getElementById(
"locationWhereIShallPlaceManyThings" );

function insertManyElements() {
for( i = 0; i < 2000; i++ ) {
var newElement = document.createElement( "span" );
var newElementText = document.createTextNode( "x " );
newElement.appendChild( newElementText );
targetForManyElements.appendChild( newElement );
}
}

If the next line is this then it's a handful of milliseconds:

insertManyElements();

If however the next line is this, upon triggering the event it takes several
seconds before the browser is responsive again:

document.onkeypress = insertManyElements;

Demos:

http://nrkn.com/temp/ffwtf/keypress.html
http://nrkn.com/temp/ffwtf/nokeypress.html

Any ideas?
 
T

Thomas 'PointedEars' Lahn

Nik said:
I really am going mad here. Firefox is going really slowly on something
that should be trivial and is in fact very fast in all of my other
browsers.

The strange thing is that for most people, it's not happening. It happens
on my machine here, and I've tried using Firefox with a clean profile,
Firefox Portable etc. with the same result. It does however happen for
some people, which is a concern.

Consider the following:

var targetForManyElements = document.getElementById(
"locationWhereIShallPlaceManyThings" );

function insertManyElements() {
for( i = 0; i < 2000; i++ ) {
var newElement = document.createElement( "span" );
var newElementText = document.createTextNode( "x " );
newElement.appendChild( newElementText );
targetForManyElements.appendChild( newElement );
}
}

If the next line is this then it's a handful of milliseconds:

insertManyElements();

If however the next line is this, upon triggering the event it takes
several seconds before the browser is responsive again:

document.onkeypress = insertManyElements;

Demos:

http://nrkn.com/temp/ffwtf/keypress.html
http://nrkn.com/temp/ffwtf/nokeypress.html

Any ideas?

ISTM you are looking for a problem to your solution. Isn't it obvious to
you that while the `load' event of a document occurs only once, the
proprietary `keypress' event can occur many times for a single key,
depending on how the keyboard driver is configured (so as to explain why it
happens for some people)?

Simply don't do this nonsense and everyone will be happier.

Besides, you have forgotten to declare `i'.


PointedEars
 
N

Nik Coughlin

Thomas 'PointedEars' Lahn said:
ISTM you are looking for a problem to your solution. Isn't it obvious to
you that while the `load' event of a document occurs only once, the
proprietary `keypress' event can occur many times for a single key,
depending on how the keyboard driver is configured (so as to explain why
it
happens for some people)?

It's not specific to onkeypress. It does the same thing with onkeyup - and
onclick too for that matter.

http://nrkn.com/temp/ffwtf/keyup.html
http://nrkn.com/temp/ffwtf/mouseclick.html
Simply don't do this nonsense and everyone will be happier.

Don't do what nonsense? Use Javascript to handle keyboard events?
 
T

Thomas 'PointedEars' Lahn

Nik said:
"Thomas 'PointedEars' Lahn":

It's not specific to onkeypress. It does the same thing with onkeyup - and
onclick too for that matter.

http://nrkn.com/temp/ffwtf/keyup.html
http://nrkn.com/temp/ffwtf/mouseclick.html

So Gecko may be still slower with adding a bunch of new SPAN child nodes
when there are many SPAN child nodes already. Does that really surprise
you?
Don't do what nonsense? Use Javascript to handle keyboard events?

Don't insert 100+ (SPAN) child nodes on one user action.

Show a *real* problem next time.


PointedEars
 
N

Nik Coughlin

Thomas 'PointedEars' Lahn said:
So Gecko may be still slower with adding a bunch of new SPAN child nodes
when there are many SPAN child nodes already. Does that really surprise
you?

There *are no* span nodes already. When I try it I find it to be slow the
first time, when the document is empty. But only when triggered by a user
action. As demonstrated above.

And yes, it does surprise me that Firefox (on a small minority of machines)
takes *several seconds* to do so, when other browsers and Firefox on most
machines can do it in considerably less than 100 milliseconds. That
surprises me a lot. That's quite a big difference.
Don't insert 100+ (SPAN) child nodes on one user action.

Why not? *Most* browsers do this in <100ms *most* of the time.
Show a *real* problem next time.

This is a real problem. I've reduced it to a simple test case which is what
I'm presenting here.

If it were just my machine then it wouldn't matter. Most of the machines
I've tried it on don't exhibit the behaviour, but unfortunately I have one
other box here that does the same thing, and your earlier report suggests
that you see it as well.
 
M

Michael Haufe (\TNO\)

Nik Coughlin said:
Why not? *Most* browsers do this in <100ms *most* of the time.

DOM interactions have always been slow, FireFox is no exception to
this rule. Don't perform a significant number of DOM calls in a loop,
or in any other construct. You will achieve significantly better
performance if you use cloneNode from some template, or by creating a
string in the loop and attach it by using the non-standard innerHTML.
Take note that older versions of FireFox are slow with innerHTML, but
would still be faster than your approach.
 
T

Thomas 'PointedEars' Lahn

Nik said:
Thomas 'PointedEars' Lahn said:
So Gecko may be still slower with adding a bunch of new SPAN child nodes
when there are many SPAN child nodes already. Does that really surprise
you?

There *are no* span nodes already. When I try it I find it to be slow the
first time, when the document is empty. [...]

I find it to be slow each time, and even slower each time a new bunch of
SPANs is added to the same document. Actually, after a few keypresses or
clicks CPU load goes up to 100% and Iceweasel hangs. Unsurprisingly.
Why not? *Most* browsers do this in <100ms *most* of the time.

It is completely unnecessary nonsense anyway.
This is a real problem. I've reduced it to a simple test case which is
what I'm presenting here.

I am curious: Why would you need to insert 100+ SPAN elements at a time in
the first place?
If it were just my machine then it wouldn't matter. Most of the machines
I've tried it on don't exhibit the behaviour, but unfortunately I have one
other box here that does the same thing, and your earlier report suggests
that you see it as well.

That was a different test case, though.


PointedEars
 
N

Nik Coughlin

Thomas 'PointedEars' Lahn said:
Nik said:
Thomas 'PointedEars' Lahn said:
Nik Coughlin wrote:
"Thomas 'PointedEars' Lahn":
Nik Coughlin wrote:
http://nrkn.com/temp/ffwtf/keypress.html
http://nrkn.com/temp/ffwtf/nokeypress.html

Any ideas?

ISTM you are looking for a problem to your solution. Isn't it obvious
to
you that while the `load' event of a document occurs only once, the
proprietary `keypress' event can occur many times for a single key,
depending on how the keyboard driver is configured (so as to explain
why it happens for some people)?

It's not specific to onkeypress. It does the same thing with onkeyup -
and
onclick too for that matter.

http://nrkn.com/temp/ffwtf/keyup.html
http://nrkn.com/temp/ffwtf/mouseclick.html

So Gecko may be still slower with adding a bunch of new SPAN child nodes
when there are many SPAN child nodes already. Does that really surprise
you?

There *are no* span nodes already. When I try it I find it to be slow the
first time, when the document is empty. [...]

I find it to be slow each time, and even slower each time a new bunch of
SPANs is added to the same document. Actually, after a few keypresses or
clicks CPU load goes up to 100% and Iceweasel hangs. Unsurprisingly.

I think that it's a Gecko problem that only happens under certain
circumstances. In the interest of trying to get it to run slowly elsewhere I
just tried it under IE6 on a horrible slow old box and even on that it only
took about half a second.
It is completely unnecessary nonsense anyway.


I am curious: Why would you need to insert 100+ SPAN elements at a time in
the first place?

It's not just inserting, testing indicates the same issue with removing or
updating.

This example is a lot closer to what I am actually doing than the minimal
test case:
http://nrkn.com/temp/ffwtf/real/

What I'm *actually doing* is emulating a terminal. Generally it will have
80x25 addressable cells, hence the 2000 iterations in the test code.

The terminal in this instance just sits there and waits for input from the
user, then updates.

Having to update all 2000 cells at once is an edge case really, most of the
time only a small number of them will change. But that is beside the point.

It seemingly works very nicely across all browsers, even older ones on older
machines, except for this problem that I am having with Firefox on two of my
own machines (one Vista, one Ubuntu), and anecdotally a couple of other
people have had the several-seconds-instead-of-less-than-100-milliseconds
problem also.
That was a different test case, though.

Yes, it was. But it seems equally likely to occur when any kind of "large"
scale DOM manipulation is done from an event handler, in a minority of
installs of Gecko browsers.
 
T

Thomas 'PointedEars' Lahn

Nik said:
Thomas 'PointedEars' Lahn said:
Nik said:
:
Nik Coughlin wrote:
It's not specific to onkeypress. It does the same thing with onkeyup -
and onclick too for that matter.
http://nrkn.com/temp/ffwtf/keyup.html
http://nrkn.com/temp/ffwtf/mouseclick.html
So Gecko may be still slower with adding a bunch of new SPAN child
nodes when there are many SPAN child nodes already. Does that really
surprise you?
There *are no* span nodes already. When I try it I find it to be slow
the first time, when the document is empty. [...]

I find it to be slow each time, and even slower each time a new bunch of
SPANs is added to the same document. Actually, after a few keypresses or
clicks CPU load goes up to 100% and Iceweasel hangs. Unsurprisingly.

I think that it's a Gecko problem that only happens under certain
circumstances. In the interest of trying to get it to run slowly elsewhere
I just tried it under IE6 on a horrible slow old box and even on that it
only took about half a second.

Time to submit a bug report, then.
It's not just inserting, testing indicates the same issue with removing or
updating.

This example is a lot closer to what I am actually doing than the minimal
test case:
http://nrkn.com/temp/ffwtf/real/

What I'm *actually doing* is emulating a terminal. Generally it will have
80x25 addressable cells, hence the 2000 iterations in the test code.

You should have told that right from the start[1]; that would have saved us
a lot of free time, as I could have told you from the start that you
*really* don't want (or need) to do that like this.

[1] <http://www.catb.org/~esr/faqs/smart-questions.html#goal>


PointedEars
 
R

rf

This example is a lot closer to what I am actually doing than the minimal
test case:
http://nrkn.com/temp/ffwtf/real/

What I'm *actually doing* is emulating a terminal. Generally it will have
80x25 addressable cells, hence the 2000 iterations in the test code.

That is decidedly *not* the way I would have implemented a terminal
emulator.
 
N

Nik Coughlin

Thomas 'PointedEars' Lahn said:
Nik said:
Thomas 'PointedEars' Lahn said:
Nik Coughlin wrote:
:
Nik Coughlin wrote:
It's not specific to onkeypress. It does the same thing with
onkeyup -
and onclick too for that matter.
http://nrkn.com/temp/ffwtf/keyup.html
http://nrkn.com/temp/ffwtf/mouseclick.html
So Gecko may be still slower with adding a bunch of new SPAN child
nodes when there are many SPAN child nodes already. Does that really
surprise you?
There *are no* span nodes already. When I try it I find it to be slow
the first time, when the document is empty. [...]

I find it to be slow each time, and even slower each time a new bunch of
SPANs is added to the same document. Actually, after a few keypresses
or
clicks CPU load goes up to 100% and Iceweasel hangs. Unsurprisingly.

I think that it's a Gecko problem that only happens under certain
circumstances. In the interest of trying to get it to run slowly
elsewhere
I just tried it under IE6 on a horrible slow old box and even on that it
only took about half a second.

Time to submit a bug report, then.

In the process of doing so. Checking to see if it's a dupe first. Not the
easiest thing to do, there is a lot of noise in Bugzilla.
It's not just inserting, testing indicates the same issue with removing
or
updating.

This example is a lot closer to what I am actually doing than the minimal
test case:
http://nrkn.com/temp/ffwtf/real/

What I'm *actually doing* is emulating a terminal. Generally it will have
80x25 addressable cells, hence the 2000 iterations in the test code.

You should have told that right from the start[1];
[...]
[1] <http://www.catb.org/~esr/faqs/smart-questions.html#goal>

You're quite right, particularly in regards to "get stuck on what they think
is one particular path towards the goal".

I had this in mind when posting:
http://www.catb.org/~esr/faqs/smart-questions.html#code

"just enough code to exhibit the undesirable behavior and no more"
I could have told you from the start that you
*really* don't want (or need) to do that like this.

Could you possibly elaborate on that a little?
 
T

Thomas 'PointedEars' Lahn

Nik said:
Thomas 'PointedEars' Lahn said:
Nik said:
What I'm *actually doing* is emulating a terminal. Generally it will
have 80x25 addressable cells, hence the 2000 iterations in the test
code.

You should have told that right from the start[1];
[...]
[1] <http://www.catb.org/~esr/faqs/smart-questions.html#goal>

You're quite right, particularly in regards to "get stuck on what they
think is one particular path towards the goal".

I had this in mind when posting:
http://www.catb.org/~esr/faqs/smart-questions.html#code

"just enough code to exhibit the undesirable behavior and no more"

ACK, I can see why these could be perceived as competing requirements.
However, mark the first paragraph of the first referred section: The reduced
test case is only useful *following* the description of the larger goal so
that we know the whole/greater context of the question. (The cljs FAQ has
the "whole context" part already but perhaps this combined recommendation
should enter the FAQ in some form, too.)
Could you possibly elaborate on that a little?

Yes. (Sorry, you asked for it ;-))

BTW, please trim your quotes more (see above). See also
<http://insideoe.com/> for dealing with the built-in bugs of your
newsreader, and <http://getthunderbird.com/> for a better one.


PointedEars
 
R

rf

Nik Coughlin said:
Care to elaborate on that? Even very briefly?

I assume you mean those black and green things from circa 1970 (I remember
them well, even coded a PC emulator for them(in C of course)). Those ones
that simply pretended to be a teletype. The ones where you typed a line of
stuff in, pressed return and some lines of data come back. Just like DOS
(and the windows command box) still work.

You don't need to address each and every cell. Terminals are line
orientated, like a teletype. You type in characters at the end of the line.
The terminal receives characters and places them at the end of the line, and
that line is usually the one at the bottom of the screen, just like in DOS.
Not always at the bottom, but it's always the last one with any data in it.
The rest of the screen is blank.

Style 25 p elements to look like a terminal (no margins, monotype font). On
keypress add the character to the end of the current line (add it to the
text node inside the p element) unless that line already has 80 characters
in it in which case move to the next line, blank that line and add the
character there. A "scroll" may be required as well. This is as easy as
removing the first p and adding a new one at the bottom.

A "clear screen" is simply emptying the text nodes in each p, or rather
replacing them with an empty string. To do what your test case above does
simply build 25 strings of random characters and put them in the text nodes.

The "cursor" (or caret if you like) is a little trickier. Chose a cursor
character that is not usually enterable from the keyboard, some nice looking
unicode character that is in the monotype font face you are using. Add it to
end of the current line and wait for a keypress. On keypress remove the
cursor, add the new character and then add in the cursor.

You could even make it smart (like some of the later DOS systems were) where
you can back arrow and insert characters in the middle of the line. A little
bit trickier, you have to pull the string apart into two and glue them back
together with the character (or cursor) in the middle but I would find that
much easier to code than trying to shuffle 80 span elements around, and
figure out what is to happen when the line overflowed.

In fact, thinking about this, you don't even need to read the DOM to get the
strings. You already have them, squirreled away in an array or something
Simply write to the DOM when any string (the current line) changes. Your
example degenerates to a bunch of string builds and exactly 25 writes to the
DOM, not 2000. A clear screen is simply assigning an empty string to 25
elements of an array followed by 25 DOM writes.

Of course using a p isn't the only one way. You might like to use 25 input
elements (writing to their value attribute) and thus gain an automatic
cursor and insert mode, after a bit of fiddling. And the lines are then
automatically packaged up for you to easily send to the host via a post
request.

In fact, I worked with a system just like that in the 70's/80's. An IBM GUI
called SPF, the precursor to ISPF.

http://en.wikipedia.org/wiki/ISPF

The "screen" was divided up into 25 "input" fields. You could type whatever
you wanted into each one (no line overflow) and return sent the whole mess
up to the mainframe to "edit" the source code being worked upon. There were
also 25 short "input" fields to the left of the screen where commands could
be entered. Things like d to delete a line, r to replicate it, c here and an
a elsewhere to copy/paste. Pretty bloody swank when the terminals used by
others used a command line interface little better than edlin.
 
R

rf

In fact, thinking about this, you don't even need to read the DOM to get
the strings. You already have them, squirreled away in an array or
something Simply write to the DOM when any string (the current line)
changes.

To elaborate on this, you are using the DOM as the storage medium for your
emulator, messy, overkill and slow. I am advocating using strings (or
something) as the storage medium and only using the DOM as the output
medium.
 
L

Lasse Reichstein Nielsen

....
Consider the following:

var targetForManyElements = document.getElementById(
"locationWhereIShallPlaceManyThings" );

function insertManyElements() {
for( i = 0; i < 2000; i++ ) {

Do remember to declare i as a local variable. Otherwise it is a global
variable, which can cause a signficant slowdown.
var newElement = document.createElement( "span" );
var newElementText = document.createTextNode( "x " );
newElement.appendChild( newElementText );
targetForManyElements.appendChild( newElement );
}
}

Is the example minimal? E.g., does the problem go away if you just add
text nodes directly, without wrapping them in span elements?
(I can't reproduce the problem in my Firefox, so I can't check it).

Could you create a document fragment, add the elements to this, and then
add the fragment at the end?

Could you try measuring the time spent in your code? I.e., do a
var t0 = new Date();
before the loop and
var t = new Date() - t0;
after the loop and then printing the time taken somhow. Maybe the extra time
is spent in the renderer after your code exits (probably not, but it's best
to be sure).


....

/L
 
T

Thomas 'PointedEars' Lahn

Lasse said:
Do remember to declare i as a local variable. Otherwise it is a global
variable, which can cause a signficant slowdown.

It becomes a property of an object in the scope chain, if that. Otherwise
you are correct.
[...] Maybe the extra time is spent in the renderer after your code exits
(probably not, but it's best to be sure).

Good thinking. Unfortunately, Gecko is known to be slower there than MSHTML
or Opera; and with this many SPAN elements ...


PointedEars
 
D

Doug Miller

You don't need to address each and every cell. Terminals are line
orientated, like a teletype. You type in characters at the end of the line.
The terminal receives characters and places them at the end of the line, and
that line is usually the one at the bottom of the screen, just like in DOS.
Not always at the bottom, but it's always the last one with any data in it.
The rest of the screen is blank.

Not all terminals are line-oriented. The IBM 3270 and the Tandem 65xx series
support both line- and block-mode communication. (In block mode, an entire
screen is transmitted or received at once.) Before commenting on the method
the OP has chosen to implement a terminal emulator, it's important to know
*which* terminal he's trying to emulate.

Of course, I wouldn't choose a cell-by-cell method for emulating a block-mode
terminal either.
 
N

Nik Coughlin

Nik said:
Thomas 'PointedEars' Lahn said:
Nik Coughlin wrote:
What I'm *actually doing* is emulating a terminal.

You should have told that right from the start[1];
[...]
I could have told you from the start that you
*really* don't want (or need) to do that like this.

Could you possibly elaborate on that a little?

Yes. (Sorry, you asked for it ;-))

Yes, I did. I'm sorry, next time I'll demand an answer rather than
politely requesting one :p

Please tell me what you had in mind. The reason I was trying to use
addressable cells is that any or all of the cells may change at any
time, and the terminal also supports color, so I need the ability to
style the background-color and color of the cells individually as well.
BTW, please trim your quotes more (see above). See also
<http://insideoe.com/> for dealing with the built-in bugs of your
newsreader, and<http://getthunderbird.com/> for a better one.

I've been using Windows Mail (replaces OE) because it's what I'm used to
and because the last time I used Thunderbird (a long time ago) it had
some peculiarities about its interface that I didn't like. I just
downloaded it again and am pleasantly surprised at how much better it's
become, so won't be using WM again. Thanks.
 
N

Nik Coughlin

I assume you mean those black and green things from circa 1970 (I remember
them well, even coded a PC emulator for them(in C of course)). Those ones
that simply pretended to be a teletype. The ones where you typed a line of
stuff in, pressed return and some lines of data come back. Just like DOS
(and the windows command box) still work.

Yes, that's what I'm doing, fairly much. Will elaborate more in response
to your response (now there's a clumsy sentence!).
You don't need to address each and every cell. Terminals are line
orientated, like a teletype. You type in characters at the end of the line.
The terminal receives characters and places them at the end of the line, and
that line is usually the one at the bottom of the screen, just like in DOS.
Not always at the bottom, but it's always the last one with any data in it.
The rest of the screen is blank.

Style 25 p elements to look like a terminal (no margins, monotype font). On
keypress add the character to the end of the current line (add it to the
text node inside the p element) unless that line already has 80 characters
in it in which case move to the next line, blank that line and add the
character there. A "scroll" may be required as well. This is as easy as
removing the first p and adding a new one at the bottom.

The problem is that terminals like DOS, most *nix terminals et al. have
the concept of being able to place the cursor at any point on the
screen, being able to use different background and foreground colors
etc., so I may need at any time to place a character at any point on the
terminal, using any background or foreground color, rather than in a
line by line fashion.
A "clear screen" is simply emptying the text nodes in each p, or rather
replacing them with an empty string. To do what your test case above does
simply build 25 strings of random characters and put them in the text nodes.

The problem is that this only works if there is no color - and I'm
sorry, in the example I gave no color was the case. As Mr PointedEars
has pointed out, I failed to state my goal beforehand, which has
needlessly complicated this discussion.

What I could do, instead of building each row out of 80 separate spans
as I am currently doing, is look for runs of the same
foreground/background color, and wrap those in a span, while leaving any
runs that are the default foreground/background color unwrapped.

This would cut down on the amount of markup, but it means potentially
changing the structure of the DOM at every update, rather than just
setting the spans up once and then changing their contents and styling.
I intuitively felt that having addressable cells would be more efficient
for this reason, but it's possible that I'm mistaken in that assumption.
Perhaps I should actually try it.
The "cursor" (or caret if you like) is a little trickier. Chose a cursor
character that is not usually enterable from the keyboard, some nice looking
unicode character that is in the monotype font face you are using. Add it to
end of the current line and wait for a keypress. On keypress remove the
cursor, add the new character and then add in the cursor.

That sounds like a good idea.

I haven't even got as far as input yet, being stuck on this problem
where I have to wait several seconds between keypresses for updates. I
could easily solve this by using a different browser or a different
computer, but the problem is that all of my usual tools are on this
computer, and I use Firebug, the Web Developer tools etc. in Firefox
extensively and would feel lost without them, so I'm labouring away here
trying to find some way to work around it instead :)
http://en.wikipedia.org/wiki/ISPF

The "screen" was divided up into 25 "input" fields. You could type whatever
you wanted into each one (no line overflow) and return sent the whole mess
up to the mainframe to "edit" the source code being worked upon. There were
also 25 short "input" fields to the left of the screen where commands could
be entered. Things like d to delete a line, r to replicate it, c here and an
a elsewhere to copy/paste. Pretty bloody swank when the terminals used by
others used a command line interface little better than edlin.

Very clever indeed. Sounds a lot like vi.

http://en.wikipedia.org/wiki/Vi
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,021
Latest member
AkilahJaim

Latest Threads

Top