Quantify GWT Debug module overhead

60 views
Skip to first unread message

jaga

unread,
Mar 30, 2012, 6:49:54 AM3/30/12
to google-we...@googlegroups.com
Hi,

According to the literature adding the GWT Debug module to your project and add onEnsureDebugID to your widgets adds overhead[1]. Can someone be more specific on what this overhead is? Also why does GWT completely remove ids anyway? Does it have anything to do with experience of ASP.net[2]?

I am considering leaving the GWT Debug module in place for production. In any case I will profile my app to make my own measurements on what this 'overhead' means.

James

Joseph Lust

unread,
Mar 30, 2012, 12:07:11 PM3/30/12
to google-we...@googlegroups.com
Jaga,

GWT needs to do UiBinding of HTML elements inserted into the DOM. A paraphrasing of this process is:
  • Made insert a new <X> element into the DOM with a custom id (i.e. gwt_id_E7D8A88).
  • Instantly do a lookup for that id and store the reference so that it is now UI bound.
  • Remove the temporary id.
This means that you see a bunch of tags with no id's when you use a DOM inspector, but they were really used. This is why GWT does not want you to set them.

To get around this you can set the attribute debugId in your UiBinder XML (GWT 2.3 & lower) or set it programmaticly at run time. We use the later so that necessary items can be references by Cucumber without the use of brittle XPaths (slow) that depend on classes (unless you're using GWT CSS obfuscation) and tag types.

Sincerely,
Joseph


Thomas Broyer

unread,
Mar 30, 2012, 12:15:32 PM3/30/12
to google-we...@googlegroups.com


On Friday, March 30, 2012 6:07:11 PM UTC+2, Joseph Lust wrote:
Jaga,

GWT needs to do UiBinding of HTML elements inserted into the DOM. A paraphrasing of this process is:
  • Made insert a new <X> element into the DOM with a custom id (i.e. gwt_id_E7D8A88).
  • Instantly do a lookup for that id and store the reference so that it is now UI bound.
  • Remove the temporary id.
This means that you see a bunch of tags with no id's when you use a DOM inspector, but they were really used. This is why GWT does not want you to set them.

In some (most?) cases, it's more like:
  • insert a placeholder <span> with a custom id
  • instantly replace that element with a widget
Should UiBinder really assign the ID back to the widget's element in this case? I don't think so.

Also, I've heard of performance penalty when there are a lot of elements with an ID set (the browser maintains a map of IDs to elements, for CSS and getElementById), but I don't know if that's still the case in modern browsers (but it could be in things like IE6 or 7, or maybe even 8).
 

To get around this you can set the attribute debugId in your UiBinder XML (GWT 2.3 & lower)

Do you mean debugId is broken in 2.4? Have you raised a bug? (or is this a known incompatibility I'm not aware of?)

Joseph Lust

unread,
Mar 31, 2012, 6:02:29 PM3/31/12
to google-we...@googlegroups.com
Thomas,

I've long wondered how the UiBinder attachment process was done. I've read here before that temporary id's were used to swap elements in and out, and it made sense.

The UiBinder docs also hint at this:
 You know that when your ui is built, a getElementById() call is made for each and every one of them. In a large page, that can add up.

Since it's Saturday, and Googling found nothing for this enigma, I dug into the UiBinder source. Most of the meat is in UiBinderGenerator and UiBinderWriter:
/** * Declare a variable that will be filled at runtime with a unique id, safe * for use as a dom element's id attribute. For {@code UiRenderer} based code, * elements corresponding to a ui:field, need and id initialized to a value * that depends on the {@code fieldName}. For all other cases let * {@code fieldName} be {@code null}. * * @param fieldName name of the field corresponding to this variable. * @return that variable's name. */ public String declareDomIdHolder(String fieldName) throws UnableToCompleteException { String domHolderName = "domId" + domId++; FieldWriter domField = fieldManager.registerField(FieldWriterType.DOM_ID_HOLDER, oracle.findType(String.class.getName()), domHolderName); if (isRenderer && fieldName != null) { domField.setInitializer("buildInnerId(\"" + fieldName + "\", uiId)"); } else { domField.setInitializer("com.google.gwt.dom.client.Document.get().createUniqueId()"); } return domHolderName; 
  } 
Given that I don't see id's in the finished browser elements, they must have been removed out, but I cannot be sure since the Run Time debugger does not allow peeking into the generator (rebinder) code. Not sure why UiBinder could not just hold on to the node reference of the insertion point, but browsers do funny things when you're ramming a ton of HTML in and you sometimes need to be asynchronous about it. 

Also, to the matter of using id's, you can, but not if the element has a field name too, however id's are now deprecated. The compiler code calls this an OldSchoolId in UiBinderWriter. Frankly I say never use an id in UiBinder, or other generated widget code, since id's are supposed to be unique and stamping out widgets with the same id just messes up your DOM.


As to the debugId not working in GWT 2.4. One of my project uses debugId attributes in the ui.xml files extensively. When I tried to upgrade to 2.4, compile kept giving errors that "debugId" was not a legal attribute for various HTML elements. My assumption is that such attributes were not vetted before 2.4. I'm not sure why vetting is now done after five years, but the HTML spec allows anything you want in there and the browser is supposed to ignore invalid values, hence why debugId works in browsers. It would be nice if "debugId" could be a whitelisted attribute.


Please if anyone else knows better how this work, do sing out.

Sincerely,
Joseph
Reply all
Reply to author
Forward
0 new messages