We are now looking into the sluggish UI in our application.
Up until now we have just assumed it was the database access, network latency, Garbage collection etc, but it now seems the major culprit is the Vaadin List.
To exlude most other factors I made myself a tiny test app:
[code]
package com.example.test_list;
import javax.servlet.annotation.WebServlet;
import com.vaadin.annotations.Theme;
import com.vaadin.annotations.VaadinServletConfiguration;
import com.vaadin.data.util.BeanItem;
import com.vaadin.data.util.BeanItemContainer;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinServlet;
import com.vaadin.shared.ui.label.ContentMode;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Component;
import com.vaadin.ui.Label;
import com.vaadin.ui.Table;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
@SuppressWarnings(“serial”)
@Theme(“valo”)
public class Test_listUI extends UI {
@WebServlet(value = "/*", asyncSupported = true)
@VaadinServletConfiguration(productionMode = false, ui = Test_listUI.class)
public static class Servlet extends VaadinServlet {
}
public static class Row {
String data = new String[20]
;
public Row(int rowNo) {
for(int col=0; col<data.length; col++) {
data[col]
= "Row " + rowNo + ", col " + col;
}
}
public String get0() { return data[0]
; }
public String get1() { return data[1]
; }
public String get2() { return data[2]
; }
public String get3() { return data[3]
; }
public String get4() { return data[4]
; }
public String get5() { return data[5]
; }
public String get6() { return data[6]
; }
public String get7() { return data[7]
; }
public String get8() { return data[8]
; }
public String get9() { return data[9]
; }
public String get10() { return data[10]
; }
public String get11() { return data[11]
; }
public String get12() { return data[12]
; }
public String get13() { return data[13]
; }
public String get14() { return data[14]
; }
public String get15() { return data[15]
; }
public String get16() { return data[16]
; }
public String get17() { return data[17]
; }
public String get18() { return data[18]
; }
public String get19() { return data[19]
; }
}
BeanItemContainer<Row> container;
Component component;
@Override
protected void init(VaadinRequest request) {
final VerticalLayout layout = new VerticalLayout();
layout.setMargin(true);
setContent(layout);
final Label message = new Label("<timing>");
layout.addComponent(message);
container = new BeanItemContainer<>(Row.class);
for(int i=1; i<100; i++) {
container.addBean( new Row(i));
}
Button button = new Button("Add plain list");
button.addClickListener(new Button.ClickListener() {
public void buttonClick(ClickEvent event) {
if(component!=null) {
layout.removeComponent(component);
}
long start = System.currentTimeMillis();
Table table = new Table("Plain text", container);
component = table;
layout.addComponent(component);
message.setValue("Plain list added in " + (System.currentTimeMillis()-start) + "ms");
}
});
layout.addComponent(button);
button = new Button("Add editable list");
button.addClickListener(new Button.ClickListener() {
public void buttonClick(ClickEvent event) {
if(component!=null) {
layout.removeComponent(component);
}
long start = System.currentTimeMillis();
Table table = new Table("Editable", container);
table.setEditable(true);
component = table;
layout.addComponent(component);
message.setValue("Editable list added in " + (System.currentTimeMillis()-start) + "ms");
}
});
layout.addComponent(button);
button = new Button("Add html table");
button.addClickListener(new Button.ClickListener() {
public void buttonClick(ClickEvent event) {
if(component!=null) {
layout.removeComponent(component);
}
long start = System.currentTimeMillis();
StringBuilder sb = new StringBuilder();
sb.append("<table>\n");
for(Object itemId : container.getItemIds()) {
sb.append("<tr>");
BeanItem<Row> beanItem = container.getItem(itemId);
for(Object propertyId : beanItem.getItemPropertyIds()) {
sb.append("<td>").append(beanItem.getItemProperty(propertyId).getValue()).append("</td>");
}
sb.append("</tr>\n");
}
sb.append("</table>\n");
Label label = new Label(sb.toString());
label.setContentMode(ContentMode.HTML);
component = label;
layout.addComponent(component);
message.setValue("HTML table added in " + (System.currentTimeMillis()-start) + "ms");
}
});
layout.addComponent(button);
}
}
[/code]I have then run this in different browsers and timed it with ?debug, from first output to last.
There are 3 buttons, each replacing the existing table with a new one.
Each button renders the same Container with 20 columns by 100 rows.
html table
The simplest one is the button that just renders it as an html table. I added this to get a sense of what the lowest possible time would be. In all browsers I got a response time of 100-200ms. This includes the network traffic and is quite acceptable.
Non-editable Vaadin list
The next one renders a non-editable Vaadin list. Chrome is almost as fast as the plain html, returning this in 250ms or so, but Firefox now takes 700ms and the different IE versions take from 900 to 1400ms.
Editable Vaadin list
The final one is the button that returns an editable Vaadin list. Chrome is still fastest, but at 2600ms it is far from fast. Firefox takes 5500ms, and IE takes from 2800ms to a whopping 22 seconds! (Only verified these extreme timings in IE10)
Conclusions?
So, at 2.6 seconds rendering time an editable table like this is just barely usable in Chrome, especially when we add in database access and all the other parts of our application.
IE10 initially rendered the table in a comparable 4 seconds. It was when I clicked again and replaced the table with a new instance that it took from 10 to 20 seconds! Already at 4 seconds, this is pretty useless, but our application will also be replacing the data (when another parent is selected) so we are seeing these 10 to 20 rendering times as well…
Note: I use default List settings, which means Vaadin fetches 10 rows or so at a time. This means that my test list is fetched in 2 separate requests. It is possible I would have gotten a bit better timings if I had tuned the page size so that it had been fetched in one go, but I don’t think it would matter much. Each actual request only takes 10-40ms.
It seems my options are to let the table remain as non-editable, and create some sort of row editor, or to just wait 1-2 months for the new Grid component…
Anyone else had a similar problem? How did you work around it?