No More Posting New Topics!

If you have a question or an issue, please start a thread in our Github Discussions Forum.
This forum is closed for new threads/ topics.

Navigation

    Quasar Framework

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search

    Some performance issues

    Framework
    3
    10
    2934
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • qyloxe
      qyloxe last edited by qyloxe

      Hi, I know, that quasar is not in performance/optimisation/efficiency mode (yet) but maybe it would be interesting for someone. In one of my apps I noticed a large raise of non referenced DOM nodes (removed from DOM but stored in process memory) and attached corresponding javascript event handlers (stored in javascript heap memory). Those nodes and events are not garbage collected - looks like memory leak. Even after pressing F5 they are not gc processed. They are removed only after pressing Ctrl+F5, so it is rather a problem for a typical user.

      After little tinkering, I isolated the most leaking code - it was placed in QTooltip. Maybe someone wiser/more experienced could confirm/reject my observation:

      Here is the code:
      0_1533031981742_e35740a3-0a06-4de8-9420-abcafc8cc493-image.png

      And here are example memory spikes (paging through QDataTable) and DOM Nodes count. This $nexttick handler is present in many groups (recalculate style, layout etc.):

      0_1533032147593_9ce4e10e-0b17-46a9-9bdb-020238cd83d2-image.png

      1 Reply Last reply Reply Quote 1
      • K
        krugeros last edited by

        I have the same issues with QDataTable. It seems like QDataTable slows down my web browsers after a few cycles of pagination and filter actions.

        1 Reply Last reply Reply Quote 0
        • rstoenescu
          rstoenescu Admin last edited by

          1. Quasar IS in in performance/optimisation/efficiency mode. But it depends on the usage. If you render 1 million components then any framework would start to cope hard with this.
          2. This is NOT an issue. The QTooltip (and QPopover, and QModal) are kept in memory and added to DOM only when they are displayed as long as the components are being rendered by Vue. The Garbage Collector works when their parent component gets destroyed (which makes sense). This is the required behaviour because tooltips, popovers and modals need to be dynamically added at the end of <body> so they get displayed on top of any other page content – and not in the same place as their parent components (which would raise another issue of inheriting CSS props from it too).
          qyloxe 1 Reply Last reply Reply Quote 1
          • qyloxe
            qyloxe @rstoenescu last edited by

            @rstoenescu
            Hi, thanks for reply. Let me clarify:

            1. the problem is observable with only 100 rows per page in QDataTable case. It is a show stopper for SPA apps on older mobile devices.

            2. as you could see on the attached screenshot, both handlers and references were not GC collected when they were no longer displayed. The listeners, nodes and js heap only grows after clicking next page in QDataTable with custom QTooltips. It seems, that the problem may be not with the adding new tooltips, popovers and modals but with disposing those no longer needed. I do not know if rows (ie dom nodes and events) in paginated table are reused but tooltips and their handlers obviously are not.

            OK, I’m not arguing anything specific, just making an observation. I’m sure that it will somehow feed your (profiling/speed/memory consumption) curiosity anyway 🙂

            1 Reply Last reply Reply Quote 0
            • rstoenescu
              rstoenescu Admin last edited by

              Ok, now it’s more clear to me what you’re reporting. Will investigate. Might be related to how Vue handles the memory. Will see.

              1 Reply Last reply Reply Quote 0
              • rstoenescu
                rstoenescu Admin last edited by

                Without a shadow of a doubt it’s not QTooltip and it’s not Quasar.

                It’s either Vue or something else (like how browser schedules for GC). I also did a quick test on https://vuejs.org/v2/guide/transitions.html#Custom-Transition-Classes --> check the example on this section, and hit “Toggle Render” a few times. DOM node count rises up. This is with very simple code:

                <div id="example-3">
                  <button @click="show = !show">
                    Toggle render
                  </button>
                  <transition
                    name="custom-classes-transition"
                    enter-active-class="animated tada"
                    leave-active-class="animated bounceOutRight"
                  >
                    <p v-if="show">hello</p>
                  </transition>
                </div>
                
                new Vue({
                  el: '#example-3',
                  data: {
                    show: true
                  }
                })
                

                This should be reported to Vue team.

                qyloxe 1 Reply Last reply Reply Quote 0
                • K
                  krugeros last edited by

                  It can be related with this issue:
                  https://github.com/vuejs/vue/issues/8507

                  1 Reply Last reply Reply Quote 0
                  • qyloxe
                    qyloxe @rstoenescu last edited by

                    @rstoenescu
                    hi,

                    I think you’re right that it is not a QToolTip. I created a jsfiddle

                    https://jsfiddle.net/unLms60y/59/

                    with this html:

                    <link rel="stylesheet" type="text/css" href="https://unpkg.com/quasar-framework@^0.17.0/dist/umd/quasar.mat.min.css">
                    <script src="https://unpkg.com/quasar-framework@^0.17.0/dist/umd/quasar.mat.umd.min.js"></script>
                    
                    <div id="q-app">
                    <q-btn @click="fetchData">first load</q-btn>
                            <q-table
                              title=""
                              :data="produkty"
                              :columns="columns"
                              row-key="id"
                              :pagination.sync="pagination"
                              :rows-per-page-options="rowsPerPage"
                              separator="horizontal"
                              dense
                              @request="requestDataTable"
                            >
                              <q-tr slot="header" slot-scope="props">
                                <q-th v-for="col in props.cols" :key="col.name" :props="props">
                                  <strong>{{col.label}}</strong>
                                </q-th>
                              </q-tr>
                              <template slot="body" slot-scope="props">
                                <q-tr :props="props">
                                  <q-td key="id" :props="props">
                                    {{props.row.id}}
                                    &nbsp;<q-btn round dense icon="add_shopping_cart" color="primary" small @click="cartAdd(props.row)"><q-tooltip>add to cart</q-tooltip></q-btn>
                                  </q-td>
                                  <q-td key="title" :props="props">{{ props.row.title }}<br><small class="text-dark">({{ props.row.url }})</small>
                                    &nbsp;<q-btn round dense icon="add_shopping_cart" color="primary" small @click="cartAdd(props.row)"><q-tooltip>add to cart</q-tooltip></q-btn>
                                  </q-td>
                                  <q-td key="url" :props="props">{{ props.row.url }}
                                    &nbsp;<q-btn round dense icon="add_shopping_cart" color="primary" small @click="cartAdd(props.row)"><q-tooltip>add to cart</q-tooltip></q-btn>
                                  </q-td>
                                  <q-td key="albumId" :props="props">
                                    {{ props.row.albumId }}
                                    &nbsp;<q-btn round dense icon="add_shopping_cart" color="primary" small @click="cartAdd(props.row)"><q-tooltip>add to cart</q-tooltip></q-btn>
                                  </q-td>
                                  <q-td key="thumbnailUrl" :props="props">{{ props.row.thumbnailUrl }}
                                    &nbsp;<q-btn round dense icon="add_shopping_cart" color="primary" small @click="cartAdd(props.row)"><q-tooltip>add to cart</q-tooltip></q-btn>
                                  </q-td>
                                </q-tr>
                              </template>
                            </q-table>
                    </div>
                    

                    and this javascript:

                    new Vue({
                      el: '#q-app',
                      data: function () {
                        return {
                          produkty: [],
                          pagination: {page: 1, rowsPerPage: 5, _sortBy: null, descending: false, rowsNumber: 1000},
                          rowsPerPage: [0, 5, 10, 15, 25, 50, 100],
                          columns: [
                            {name: 'albumId', field: 'albumId', label: 'albumId', required: false, align: 'left', sortable: false},
                            {name: 'id', field: 'id', label: 'id', required: false, align: 'left', sortable: false},
                            {name: 'title', field: 'title', label: 'title', required: true, align: 'left', sortable: false},
                            {name: 'url', field: 'url', label: 'url', required: true, align: 'left', sortable: false},
                            {name: 'thumbnailUrl', field: 'thumbnailUrl', label: 'thumbnailUrl', required: true, align: 'right', sortable: false}
                          ]
                        }
                      },
                      mounted () {
                        // this.fetchData()
                      },
                      methods: {
                        async requestDataTable ({pagination}) {
                          this.pagination.page = pagination.page
                          this.pagination.rowsPerPage = pagination.rowsPerPage
                          await this.fetchData()
                        },
                        async fetchData () {
                          this.produkty = []
                          // (this.pagination.page - 1) * this.pagination.rowsPerPage, this.pagination.rowsPerPage
                    			response = await fetch('https://jsonplaceholder.typicode.com/photos/')
                          json = await response.json()
                          this.produkty = json.slice(0,this.pagination.rowsPerPage)
                        },
                        cartAdd (item) {
                          this.$q.notify('add: ' + item.title)    
                        }
                    	}
                    })
                    

                    the profiling session:
                    click first load button
                    click next page
                    change records per page to 100
                    click next page
                    click some qtooltips
                    click next page
                    click next page
                    change records per page to 5
                    click next page
                    click next page

                    …and it seems OK:

                    0_1534284531793_0fab5113-b32a-4ae6-8575-6bfd778b8896-image.png

                    I was curious if changing records per page from 100 to 5 will release memory and it released as you said - which you can see on the chart.

                    So, in my application the memory leak still exists. It needs further investigation. As for now I’m assuming that it is some combination of vue, vuex, router, i18n, quasar interaction (ha ha).

                    BTW debugging such leaks is extremely hard. I really would like to have some “developer mode” where quasar would scream to me (in console log) - “hey - you’re leaking those objects and it’s not my fault, you should check this and that”. Oh, sweet dreams 🙂

                    1 Reply Last reply Reply Quote 0
                    • rstoenescu
                      rstoenescu Admin last edited by

                      Like I showed you earlier, it should be reported to Vue with the simple example (that I copy-pasted) from their docs.

                      1 Reply Last reply Reply Quote 0
                      • rstoenescu
                        rstoenescu Admin last edited by

                        Just open that link in vue docs and see the DOM node count rising up.

                        1 Reply Last reply Reply Quote 0
                        • First post
                          Last post