Task management made simple
Sheepdog helps you maintain your async tasks and gives you useful derived state in your Svelte app.
Because managing tasks shouldn't feel like chasing sheep.
Code
<script> import { task, timeout } from '@sheepdog/svelte';
let searchTask = task.restart(async function(value) { await timeout(500); let response = await fetch('/my-favourite-sheep?search=' + value); return await response.json(); });</script>
<label for="search">Search</label><input name="search" type="text" on:input={(event) => searchTask.perform(event.target.value)}/>
{#if $searchTask.isRunning} Loading...{:else if $searchTask.lastSuccessful?.value.length} <ul> {#each $searchTask.lastSuccesful.value as name} <li>{name}</li> {/each} </ul>{:else} No sheep found{/if}<script> let _currentValue; let timeout; let search = (value) => { if (timeout) { clearTimeout(timeout); }
let _timeout = setTimeout(async () => { let response = await fetch('/my-favourite-sheep?search=' + value); let results = await response.json(); // only set results if this is the last started search if (timeout === _timeout) { currentValue = results; timeout = undefined; } }, 500); timeout = _timeout; };
$: isRunning = Boolean(timeout); $: currentValue = _currentValue;</script>
<label for="search">Search</label><input name="search" type="text" on:input={(event) => search(event.target.value)}/>
{#if timeout} Loading...{:else if currentValue?.length} <ul> {#each currentValue as name} <li>{name}</li> {/each} </ul>{:else} No sheep found{/if}import { task, timeout } from "@sheepdog/vanilla";
const container = document.getElementById('search-container');container.innerHTML = ` <label for="search">Search</label> <input name="search" type="text" /> <div id="output"></div> `;
const searchInput = container.querySelector('input[name="search"]');const outputContainer = container.querySelector('#output');
const search = task( async function* (value) { yield timeout(500); const response = yield fetch('/my-favourite-sheep?search=' + value); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return yield response.json(); }, { kind: 'restart' });
search.on('start', () => { outputContainer.innerHTML = 'Loading...';});
search.on('error', () => { outputContainer.innerHTML = 'There was an error';});
search.on('instance-success', () => { const value = search.lastSuccessful.value outputContainer.innerHTML = value && value.length ? ` <ul> ${value.map((name) => `<li>${name}</li>`).join('')} </ul> ` : 'No sheep found';});
searchInput.addEventListener('input', (event) => { search.perform(event.target.value);})let timeout;let currentValue;let isRunning = false;
const container = document.getElementById('search-container');container.innerHTML = ` <label for="search">Search</label> <input name="search" type="text" /> <div id="output"></div>`const searchInput = container.querySelector('input[name="search"]');const outputContainer = container.querySelector('#output')
const search = (value) => { if (timeout) { clearTimeout(timeout); }
const _timeout = setTimeout(async () => { try { const response = await fetch('/my-favourite-sheep?search=' + value); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const results = await response.json();
if (timeout === _timeout) { currentValue = results; timeout = undefined; isRunning = false; render(); } } catch (error) { console.error('Error fetching sheep:', error); currentValue = null; timeout = undefined; isRunning = false; render(); } }, 500); timeout = _timeout; isRunning = true; render();};
const render = () => { outputContainer.innerHTML = isRunning ? 'Loading...' : currentValue && currentValue.length ? ` <ul> ${currentValue.map(name => `<li>${name}</li>`).join('')} </ul> ` : 'No sheep found';};
searchInput.addEventListener('input', (event) => search(event.target.value));
render();Demo
- Autumn
- Buttercup
- Chloe
- Dolly
- Emma
- Freddie
Task modifiers
Specify what your task should do if there's another instance already running.
You can click an individual task instance to cancel it