I have tracked down the issues in slow IE performance when adding focus
events to 1000's of elements.
I created a simple page with 1000 normal links using a listview, then
measured the performance of the wicket-ajax.js
Wicket.Focus.attachFocusEvent method. It would take about 3000ms on
page load, and around 500ms on each ajax response (tested using a simple
ajax link that does nothing in the onClick() method).
When the focus event is added to an element in IE, wicket-event.js
Wicket.Event.getId will add an id to any element that does not have
one. This takes 2200ms for my test page.
If use setOutputMarkupId(true) on my links, then Wicket.Event.getId
doesn't create one, and the Wicket.Focus.attachFocusEvent time drops to
700ms the ajax response time is unaffected.
NOTE: if you create millions of links, make sure you use
.setOutputMarkupId(true) so this focus code doesn't have to create one
for you.
We can get these numbers down by fixing a function in wicket-ajax.js
Wicket.Focus.setFocusOnElements:
setFocusOnElements: function (elements)
{
// we need to cache array length because IE will try to recalculate
// the collection of elements every time length() is called
which can be quite expensive
// if the collection is a result of getElementsByTagName or a
similar function.
var len=elements.length;
for (var i=0; i< len; i++)
{
if (elements[i].wicketFocusSet != true)
{
Wicket.Event.add(elements[i],'focus',Wicket.Focus.setFocus);
Wicket.Event.add(elements[i],'blur',Wicket.Focus.blur);
elements[i].wicketFocusSet = true;
}
}
},
Fetching the elements.length once will bring the numbers down to 220ms
for page load and 30ms for ajax update.
Igor committed the "var len=elements.length;" change into 1.3.x and
1.4.x already, so that should be all good :)
As a comparision... firefox takes 70ms for Wicket.Focus.attachFocusEvent
on page load and 5ms for ajax response.
-jason lea
James Carman wrote:
Okay, since this code does show that the problem is with the focus
stuff and we have conflicting goals here, what are we going to do to
move forward? Obviously, the IE JS engine is way too darn slow to
handle this code. Is there some optimization we can do here? Should
we file a JIRA? Is there one change in particular that made this so
slow in IE? Do we back that out until a better alternative is known?
Why am I asking so many questions? :) Sorry, too much coffee this
morning.
2009/4/17 Peter Gardfjäll <[email protected]>:
Sure,
here goes. I have added both the java and the js file to the same Java package:
WicketAjaxJsPatch.java
==================
/**
* {...@link IBehavior} that should be added to {...@link Page}s that need to
prevent
* the page load performance penalty incurred when wicket-ajax.js traverses all
* <a> tags in the page markup.
*
* <p/>
* For background information, see <a
href="http://www.nabble.com/wicket-ajax-and-IE-performance-problems-for-pages-with-many-links-td23078336.html"
* >this mailing list thread</a>
* <p/>
* This behavior simply makes sure that our patch gets applied to wicket-ajax.js
* (by forcing wicket-ajax.js to be added to the page head prior to
* wicket-ajax-patch.js).
*
*/
public class WicketAjaxJsPatch extends AbstractDefaultAjaxBehavior {
@Override
public void renderHead(IHeaderResponse response) {
super.renderHead(response);
response.renderJavascriptReference(new ResourceReference(
WicketAjaxJsPatch.class, "wicket-ajax-patch.js"));
}
@Override
protected void respond(AjaxRequestTarget target) {
// Does nothing. The fact that we are extending
// AbstractDefaultAjaxBehavior means that we will pull in
// wicket-event.js and wicket-ajax.js. The job of this behavior is to
// make sure that our wicket-ajax-patch.js script gets added to the page
// head after those scripts.
}
}
wicket-ajax-patch.js
===============
/**
* Overrides the attachFocusEvent function registered by wicket-ajax.js.
* The original version traverses all anchor and button tags on the page
* which incurs a major performance penalty on pages with many links.
* This version skips these elements in the scanning.
*/
if (typeof(Wicket) != "undefined") {
if (typeof(Wicket.Focus) != "undefined") {
// Deregister old attachFocusEvent function
handlers = Wicket.Event.domReadyHandlers;
filteredHandlers = new Array();
for(i = 0; i < handlers.length; i++) {
if (handlers[i] != Wicket.Focus.attachFocusEvent) {
filteredHandlers.push(handlers[i]);
}
}
Wicket.Event.domReadyHandlers = filteredHandlers;
// Redefine and re-register attachFocusEvent
Wicket.Focus.attachFocusEvent=function() {
Wicket.Focus.setFocusOnElements(document.getElementsByTagName("input"));
Wicket.Focus.setFocusOnElements(document.getElementsByTagName("select"));
Wicket.Focus.setFocusOnElements(document.getElementsByTagName("textarea"));
//Wicket.Focus.setFocusOnElements(document.getElementsByTagName("button"));
//Wicket.Focus.setFocusOnElements(document.getElementsByTagName("a"));
}
Wicket.Event.addDomReadyEvent(Wicket.Focus.attachFocusEvent);
}
}
Attaching the behavior
=================
What I do then is to add the WicketAjaxJsPatch to the page by doing.
page.add(new WicketAjaxJsPatch());
It seems to be doing its job for me. Please tell me if it doesn't work.
cheers, Peter
On Fri, Apr 17, 2009 at 12:15 PM, James Carman
<[email protected]> wrote:
Did that code actually work for you? I tried adding this js, but i
couldn't get it to show up in the correct place. And, when I did, it
didn't seem to improve much. Care to share your code?
2009/4/17 Peter Gardfjäll <[email protected]>:
I have written a simple WicketAjaxJsPatch Behavior which simply adds
the aforementioned javascript to the page.
In our application, we have several pages that suffer from the same problem.
It would be tedious to have to update all of these pages one-by-one.
So is there any way for me to add this Behavior to my parent page
(which other pages extend) and still have the javascript rendered last
in the head?
regards, Peter
2009/4/17 Peter Gardfjäll <[email protected]>:
Thanks Igor,
the suggested workaround seems to work fine. However, it is not enough
to just override the attachFocusEvent function -- you also need to
deregister the previously registered function. I did as follows (I
apologize for the lack of elegance, I'm not a js expert):
if (typeof(Wicket) != "undefined") {
if (typeof(Wicket.Focus) != "undefined") {
// Deregister old attachFocusEvent function
handlers = Wicket.Event.domReadyHandlers;
filteredHandlers = new Array();
for(i = 0; i < handlers.length; i++) {
if (handlers[i] != Wicket.Focus.attachFocusEvent) {
filteredHandlers.push(handlers[i]);
}
}
Wicket.Event.domReadyHandlers = filteredHandlers;
// Redefine and re-register attachFocusEvent
Wicket.Focus.attachFocusEvent=function() {
Wicket.Focus.setFocusOnElements(document.getElementsByTagName("input"));
Wicket.Focus.setFocusOnElements(document.getElementsByTagName("select"));
Wicket.Focus.setFocusOnElements(document.getElementsByTagName("textarea"));
//Wicket.Focus.setFocusOnElements(document.getElementsByTagName("button"));
//Wicket.Focus.setFocusOnElements(document.getElementsByTagName("a"));
}
Wicket.Event.addDomReadyEvent(Wicket.Focus.attachFocusEvent);
}
}
By the way, I believe that this is, or has the potential of becoming,
a major stumbling block for others.
Should it be regarded as a bug?
kind regards, Peter
On Thu, Apr 16, 2009 at 6:23 PM, Igor Vaynberg <[email protected]> wrote:
you can try adding this to the head after wicket-ajax.js
<script>
if (Wicket!="undefined") {
if (Wicket.Focus!="undefined") {
Wicket.Focus.attachFocusEvent=function() {
Wicket.Focus.setFocusOnElements(document.getElementsByTagName("input"));
Wicket.Focus.setFocusOnElements(document.getElementsByTagName("select"));
Wicket.Focus.setFocusOnElements(document.getElementsByTagName("textarea"));
//Wicket.Focus.setFocusOnElements(document.getElementsByTagName("button"));
//Wicket.Focus.setFocusOnElements(document.getElementsByTagName("a"));
}
}
}
-igor
On Thu, Apr 16, 2009 at 9:16 AM, James Carman
<[email protected]> wrote:
So, we understand what's slowing us down? Any way to turn that stuff
off on our end to get stuff working? I've got a release going out the
door that's slow as heck on IE right now.
On Thu, Apr 16, 2009 at 12:03 PM, Igor Vaynberg <[email protected]> wrote:
this code is there so we can track focus and properly restore it after
ajax modifies the dom. i am not sure why we need to track and restore
focus on anchors, it is only important when you are typing so that the
cursor doesnt move elsewhere - so only for textfields and textareas.
johan, matej says you wanted to track focus for anchors, whats the deal?
-igor
2009/4/16 Peter Gardfjäll <[email protected]>:
Hi James,
I'm pretty sure that links are part of the problem.
To verify this, try replacing all <a> tags with e.g. <span> and see if
you can spot any difference in response time.
Alternatively, try replacing/commenting out ajax components/behaviors
on your page to prevent wicket-ajax.js from being pulled into the
page.
cheers, Peter
On Thu, Apr 16, 2009 at 3:52 PM, James Carman
<[email protected]> wrote:
Peter,
I have experienced similar problems just recently. I didn't narrow it down
to the fact that the links were the problem, as you have, though! I have
been racking my brains trying to figure this thing out. My page is similar,
a table with lots of cells in them that are links. I've turned off CSS and
other stuff trying to find the bottleneck. I didn't think for a moment that
it might be the links.
James
2009/4/16 Peter Gardfjäll <[email protected]>
Hi all,
I am working on a wicket application intended to be executed both on
FF3 and IE7.
While working on this application I have discovered that the rendering
of some pages are a lot slower in IE.
The pages that were significantly slower on IE have a couple of things
in common: they are ajax-enabled and have lots of links.
These pages all appear to freeze for a while after all data has been
transferred, but before the page becomes responsive.
The reason (or at least one of the reasons) is that wicket-ajax.js,
which gets pulled in whenever an Ajax component/behavior is added to a
page, registers a function
(addDomReadyEvent(Wicket.Focus.attachFocusEvent)) that traverses all
{input,select,a,textarea,button} tags in the DOM tree when the page
has been loaded.
I timed this function for one of my pages (containing a single big
table with around 300 rows, with each row having about six links).
When the function is registered, the fireDomReadyHandlers in
wicket-event.js takes 2400 ms to execute, compared to 700 ms when not
registered. In firefox, the corresponding numbers are about 470 ms and
400 ms.
Hence, there seems to be quite a performance penalty involved in
loading ajax pages with lots of links in IE7.
I'm a bit worried about this overhead, particularly since I have a
rather fast machine (a lot better than most of the end users anyway).
I would not be surprised if clients see double page load times.
Have anyone on this list experienced similar problems?
Is this a known issue? (I have not been able to find anything similar
on the mailing list)
Any suggestions or pointers are welcome.
best regards, Peter
/PS By the way, I am using wicket 1.3.5.
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]