JavaEar 专注于收集分享传播有价值的技术资料

如何在渲染8000多个项目时优化Mustache渲染速度? (How can I optimize Mustache rendering speed when rendering 8000+ items?)

I'm trying to render a table so the template is pretty simple; the row template looks like this:

  <script type=\"text/mustache\" id=\"template-list-records\">
  {{#.}}
   <tr>
    <td>{{airport_code}}</td>
    <td>{{city_code}}</td>
    <td class=\"pull-right\">
     [<a href=\"result.mics?m_uid={{airport_code}}\" class=\"listlink\">details</a>]
    </td>
   </tr>
  {{/.}}
  </script>

The problem is that rendering speeds starts to slow down exponentially when rendering more than 1000 results (I'm guessing it slows down exponentially all the time :) but with 1000+ results is noticeable that rendering speed is not linear). Now, at 4000 results, the page loads in 2.3 seconds. At 7000 results, rendering time is 7.3 seconds, and rendering the full result set (around 8500 results) takes 10 seconds. Now, I don't need to speed it up faster than 8 seconds for full result load (since that's the amount of time that the old functionality took to render the page), that would be a bonus :), but I still need to shave 2 seconds. I've looked at the Timeline inspector, the time is spent on rendering; rendering starts after 2.5 seconds.

I'm guessing part of the problem could be my laptop (I have some graphic card issues), but still, I'm interested if there's a way to speed this up, e.g. precompile the table with 8500 rows and add/remove rows if needed (this really is an airport list table so the number doesn't change often, and when it does, it doesn't change by much).

3个回答

    最佳答案

  1. 英文原文

    New idea: why not render the page incrementally then? I imagine that 8500 rows is quite a lot of "pages" (certainly around 200 "pages" on a 1080p screen) so you could easily implement a continuous scrolling mechanism where you keep rendering data in small chunks as needed.

    Say for starters you begin rendering the first 500 items (which is already a lot), then as the user starts scrolling and approaches around 80% of the total scroll size you render 200 extra rows. You keep doing this until you run out of rows to render.

    In the case you have a requirement that says you need to have everything available at once (so that users can ctrl+F for example) you could still try rendering in chunks: instead of feeding your template with the entire data set, break it down in sets of 500 and call Mustache as many times as needed with these smaller sets. If it still clogs, add a small timeout between calls to improve the perceived responsiveness.

    TBH, I re-read your question and most of your time seems to be spent on the browser trying to calculate your table layout, so these suggestions should work fine for your case. As a last resort you could try with CSS table-layout: fixed; which will greatly speed up your table rendering but will also in turn force you to manually define the column widths as the table will no longer dynamically adapt the column width based on its contents.


    中文翻译

    新想法:为什么不逐步渲染页面呢?我想8500行是相当多的" 页面" (在1080p屏幕上肯定大约200" 页" ),因此您可以轻松实现连续滚动机制,您可以根据需要以小块的形式呈现数据。

    首先说你开始渲染前500个项目(已经很多),然后当用户开始滚动并接近总滚动大小的80%时,你会渲染200个额外的行。你继续这样做,直到用尽渲染的行为止。

    如果您有一个要求说您需要一次提供所有内容(例如用户可以按Ctrl + F),您仍然可以尝试以块的形式呈现:而不是将模板与整个数据集一起提供,将它分解为500组并根据需要多次调用Mustache与这些较小的组。如果它仍然堵塞,请在调用之间添加一个小的超时,以提高感知的响应能力。

    TBH,我重新阅读了你的问题,你的大部分时间似乎花在浏览器上,试图计算你的表格布局,所以这些建议应该适用于你的情况。作为最后的手段,您可以尝试使用CSS table-layout:fixed; ,这将大大加快您的表格渲染速度,但也会强制您手动定义列宽,因为表格将不再动态根据其内容调整列宽。

    New idea: why not render the page incrementally then? I imagine that 8500 rows is quite a lot of "pages" (certainly around 200 "pages" on a 1080p screen) so you could easily implement a continuous scrolling mechanism where you keep rendering data in small chunks as needed.

    Say for starters you begin rendering the first 500 items (which is already a lot), then as the user starts scrolling and approaches around 80% of the total scroll size you render 200 extra rows. You keep doing this until you run out of rows to render.

    In the case you have a requirement that says you need to have everything available at once (so that users can ctrl+F for example) you could still try rendering in chunks: instead of feeding your template with the entire data set, break it down in sets of 500 and call Mustache as many times as needed with these smaller sets. If it still clogs, add a small timeout between calls to improve the perceived responsiveness.

    TBH, I re-read your question and most of your time seems to be spent on the browser trying to calculate your table layout, so these suggestions should work fine for your case. As a last resort you could try with CSS table-layout: fixed; which will greatly speed up your table rendering but will also in turn force you to manually define the column widths as the table will no longer dynamically adapt the column width based on its contents.

    新想法:为什么不逐步渲染页面呢?我想8500行是相当多的" 页面" (在1080p屏幕上肯定大约200" 页" ),因此您可以轻松实现连续滚动机制,您可以根据需要以小块的形式呈现数据。

    首先说你开始渲染前500个项目(已经很多),然后当用户开始滚动并接近总滚动大小的80%时,你会渲染200个额外的行。你继续这样做,直到用尽渲染的行为止。

    如果您有一个要求说您需要一次提供所有内容(例如用户可以按Ctrl + F),您仍然可以尝试以块的形式呈现:而不是将模板与整个数据集一起提供,将它分解为500组并根据需要多次调用Mustache与这些较小的组。如果它仍然堵塞,请在调用之间添加一个小的超时,以提高感知的响应能力。

    TBH,我重新阅读了你的问题,你的大部分时间似乎花在浏览器上,试图计算你的表格布局,所以这些建议应该适用于你的情况。作为最后的手段,您可以尝试使用CSS table-layout:fixed; ,这将大大加快您的表格渲染速度,但也会强制您手动定义列宽,因为表格将不再动态根据其内容调整列宽。

  2. 参考答案2
  3. Did you try alternate Mustache implementations like Hogan or Handlebars?

    Your template is quite small so there's not much you will win by using the pre-compiled templates feature, but specially in the case of Hogan it is finely tuned to speed up the rendering algorithm as much as possible, so there's a chance that by simply using an alternate implementation than vanilla Mustache will already fix your problems.

    Also, if you are not already on the latest version of Mustache.js you could try simply upgrading. Older versions (about 1.5 years old) had serious performance issues.

  4. 参考答案3
  5. How do you add mustache-rendered HTML into your DOM?

    Try add rendered code in one point instead of continuous inserting.

    slow, many insertions:

    for () {
      table.innerHTML = table.innerHTML + Mustache.render(row);
    }
    

    faster, 1 insert:

    var buffer = '';
    for () {
      buffer = buffer + Mustache.render(row);
    }
    table.innerHTML = buffer;