Svelte reversing table of 500 rows feels slow?

Viewed 563

I created table of 500 rows, and reversing it on click feels slow, subjectively like 500ms or so.

Is it reasonable performance? I have a feeling that reversing table of 500 lines in JS should be faster.

Svelte demo and Pure JS demo.

Pure JS feels much faster than Svelte

Table.svelte

<script>
  import Cell from "./Cell.svelte"
  
  const template = {
    name: "Barrick Gold Corp",
    symbol: "ABX",
    has_options: true,
    ib_symbol: "GOLD NYSE USD",
    ib_osymbol: "GOLD CBOE USD",
    risk: 0,
    quality: 0,
    brand: 0
  }

  let rows = []
  let id = 0
  for (let i = 0; i < 500; i++) {
    let row = [id++]
    for (let key in template) row.push(("" + template[key]) + i)
    rows.push(row)
  }  
</script>

<table>
  <button on:click={() => rows = rows.reverse()}>change order</button>
  {#each rows as row (row[0])}
    <tr>
      {#each row as cell, j (`${row[0]},${j}`)}
        <Cell value={cell} />
      {/each}
    </tr>
  {/each}
</table>
<script>
  import StringView from "./StringView.svelte"
  
  export let value
</script>

<svelte:component this={StringView} value={value}/>
<script>
  export let value
</script>

<td>{value}</td>

P.S.

Svelte demo with additional Row element performance feels same as for original svelte version.

And a version with just single table element without Row and Cell elements, feels a bit faster

1 Answers

I first thought that it has something to do with the index not working properly, but when adding a 'slice' button and a fade-effect it seems to work fine -> the first item fades out and after it was totally removed the other elements move up.

SEE THIS slightly modified version of yours

  • 'slice' button and effect on StringView added
  • timer in console tracking time before -> after Update

Nevertheless, since I already wondered how to properly define the id on arrays an nested each loops (Nested each loops over array in Svelte - how to set unique id / key?) I made a version with objects instead of row-arrays and just one Component for the rows. When comparing the time for updating, it's almost twice as fast ( firstLoad/Update --> ≈700ms/250ms --> 330ms/160ms (in Firefox)) -> See this REPL

I'm still wondering if this might be optimized, since even when the id/key seems to work, every TableRow-Component logs an Update when the order is reversed or the first element is sliced. I once made a very simple example which behaves differently and only elments without id log an update -> see this REPL

(this part of your code could be written shorter ->

<script>
    function reverse(list) { 
        list = [...list]
        list.reverse()
        return list
    }
</script>
<button on:click={() => rows = reverse(rows)}>change order</button>

like this --->

<script>
    function reverseRows() { 
      rows = rows.reverse()
    }
</script>
<button on:click={reverseRows}>change order</button>

The code of the Row-Object-Component-Solution ->

<!--[App.svelte]-->
<script>
    import { beforeUpdate, afterUpdate } from 'svelte';
    import TableRow from './TableRow.svelte';
    
    beforeUpdate(() => {
//      console.log('before Update')
        console.time('time to update');
    });
    afterUpdate(() => {
//      console.log('after Update')
        console.timeEnd('time to update')
    });
    
    const template = {
    name: "Barrick Gold Corp",
    symbol: "ABX",
    has_options: true,
    ib_symbol: "GOLD NYSE USD",
    ib_osymbol: "GOLD CBOE USD",
    risk: 0,
    quality: 0,
    brand: 0
  }

    let rowsAsObj = []
    
    for(let i = 0; i< 500; i++){
        let row = {id: i,}
        for( let key in template){
            row[key] = `${template[key]}${i}`           
        }
        rowsAsObj.push(row)
    }   
    function reverse() { 
        rowsAsObj = rowsAsObj.reverse();
    }
    function slice(){
        rowsAsObj = rowsAsObj.slice(1)
    }
</script>

    <button on:click={reverse}>change order</button>
    <button on:click={slice}>slice</button>

<table>
    {#each rowsAsObj as row (row.id)}
        <TableRow {row}/>
    {/each}
</table>

<style>
    table {
        border-collapse: collapse;
        width: 100%;
    }
</style>
<!--[TableRow.svelte]-->
<script>
    import { fade } from 'svelte/transition'
    
    import { afterUpdate } from 'svelte';
        afterUpdate(() => {
//      console.log('TableRow updated')
    });
    
    export let row;
</script>

<tr transition:fade="{{duration: 800, delay: 800}}">
    {#each Object.values(row) as cell}
        <td>
            {cell}
        </td>
    {/each}
</tr>

<style>
    
    td {
        padding: 5px;
        border-bottom: 1px solid grey;
    }
    
</style>
Related