Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to do polling in svelte?

Tags:

polling

svelte

I have a specific app which should do the following:

  1. You have a list of jobs to inspect
  2. When you click a job you get a detail view
  3. The detail view will poll the API to see live progress updates

I did a basic implementation in the following REPL: https://svelte.dev/repl/fcdce26dc0d843dbb4b394dcd2c838af?version=3.20.1

There are a couple of issues with this approach:

  1. The Job.svelte view should basically reset when you provide a new id, and clear out any previous poller, but now it's super awkward with a reactive statement at the bottom
  2. Because the poller does an asynchronous fetch it can happen that the timeout handler poller is cleared even though the handler is executing already. This causes multiple poller loops to occur (you can reproduce this by clicking through the job list at random intervals between 0 and 2 seconds)
  3. The current approach is not developer friendly and is easily broken. The 'bug' above can be fixed by keeping track of a reference/lock kind of thing but then it's even harder to wrap your head around.

For this use case, what is a better way of implementing it (in Svelte)?

Thanks a lot!

like image 771
Wilco Avatar asked Oct 21 '25 16:10

Wilco


1 Answers

The Job.svelte view should basically reset when you provide a new id, and clear out any previous poller, but now it's super awkward with a reactive statement at the bottom

Like a previous reply already pointed out, this is the Svelte way. It's awkward at first, until you realize it's very simple, handy and elegant.

There are two things I would improve in your code:

  • do away with the messy cache per ID + single progress value assignment ; this is what causes your late fetches to display visually (a late fetch reply in itself is not a bug, displaying it to your user is, however) ; I simply renamed your cache object to progress and chose to display progress[id], this way a late fetch reply will update in the background, but not interfere visually with your currently displayed job
  • use setInterval instead of multiple setTimeout for periodic polling
<script>
    export let id

    let progress = {}
    let poller

    const setupPoller = (id) => {
        if (poller) {
            clearInterval(poller)
        }
        poller = setInterval(doPoll(id), 2000)
    }

    const doPoll = (id) => async () => {
        console.log(`polling ${id}`)
        progress[id] = await new Promise(resolve => setTimeout(() => {
            resolve((progress[id] || 0) + 1)
        }, 500))
    }

    $: setupPoller(id)
</script>

<div>
    <p>
        ID: {id}
    </p>
    <p>
        Progress: {progress[id] || 0}
    <p>
</div>

See this REPL

like image 105
Thomas Hennes Avatar answered Oct 25 '25 02:10

Thomas Hennes