Thymeleaf Select Option Performance Issue

2020-07-25 07:12发布

问题:

I've been messing around with Spring MVC 5 and Thymeleaf 3.0 lately and have noticed something strange. I've started to implement a dropdown list from the tutorial on the site and have noticed some performance issues. If I use the following code, it takes around 5.5 seconds for my page to render a dropdown list of about 100 items.

<select th:field="*{item}">
    <option th:each="item : ${items}" 
            th:value="${item.getId()}" 
            th:text="${item.getValue()}"></option>
</select>

On the other hand, if I use the following code, my page renders in about 150ms.

<div th:each="item : ${items}">
    <span th:text="${item.getId()}"/>
    <span th:text="${item.getValue()}"/>
</div>

I've looped through the list of items in my controller and printed out the values to see if their was any slowdown with getting data from the database, but grabbing items from the controller happened instantly. I've also tried rendering different html elements in the select tag for testing purposes and even though it isn't valid html, it still renders the page quickly.

The only time I experience an extreme amount of lag on page rendering is when I use a th:each inside of a select tag on options. Does Thymeleaf handle select tags differently? I would think that if the same list of items, calling the same methods can render a page in 130ms by looping through divs, it should be able to create options at a comparable rate, instead of taking 5.5 seconds.

Has anyone encountered an issue like this before? I did some searching and found that there were performance issues looping in Thymeleaf, but those cases had upwards of 100,000 records, where my list is about 100 items. Any help would be greatly appreciated.

Update

I've narrowed down the issue to performing poorly on th:field="*{item}". If I run the following code, the page loads instantly.

<select>
    <option th:each="item : ${items}" 
            th:value="${item.getId()}" 
            th:text="${item.getValue()}"></option>
</select>

Once I try to bind the select using th:field="*{item}", the page hangs for around 5.5 seconds. Is there any reason why binding using th:field would cause an issue with lag?

回答1:

I had the same problem with page creation taking over a minute for the select/option part. My code was a bit different as I had the options inside a table, but I don't think that matters. My initial code looked like this:

<tr th:each="scorePart,rowStat : ${song.scoreParts}">
    <td>
        <select th:field="*{scoreParts[__${rowStat.index}__].instrument}">
            <option th:each="i2 : ${allInstruments}"
                    th:value="${i2.id}"
                    th:text="${i2.name}">bla</option>
        </select>
    </td>
    <td> more data... </td>
</tr>

But then I added the id to the field part:

<tr th:each="scorePart,rowStat : ${song.scoreParts}">
    <td>
        <select th:field="*{scoreParts[__${rowStat.index}__].instrument.id}">
            <option th:each="i2 : ${allInstruments}"
                    th:value="${i2.id}"
                    th:text="${i2.name}">bla</option>
        </select>
    </td>
    <td> more data... </td>
</tr>

And then everything works. Same results both cases, only the second one is without delay.



回答2:

This post is old, but hope I can help someone with the same problem. This happened to me some days ago. Requests where taking more than 40 seconds to complete when mapping a field to a list of objects. And if you map the attribute th:field only to the id, Spring will not serialize the whole object, only the id, when returning it to controller. The solution I found was to recreate the output that Thymeleaf produces, with a different syntax.

Instead of this:

<select th:field="*{item}">
    <option th:each="item : ${items}" 
            th:value="${item.getId()}" 
            th:text="${item.getValue()}"></option>
</select>

Do this:

<select name="item" id="item">
    <option th:each="it : ${items}"
            th:selected ="${it.getId()} == *{item.getId()}"
            th:value="${item.getId()}" 
            th:text="${item.getValue()}"></option>
</select>

The output will be the same, but the page will load 30 times faster and it will maintain the whole object "item".