Как сделать опрос в стройте? - PullRequest
0 голосов
/ 23 апреля 2020

У меня есть определенное c приложение, которое должно выполнять следующие действия:

  1. У вас есть список проверяемых заданий
  2. При нажатии на задание вы получаете подробный вид
  3. Подробное представление будет опрашивать API, чтобы увидеть обновления в реальном времени

Я выполнил базовую c реализацию в следующем REPL: https://svelte.dev/repl/fcdce26dc0d843dbb4b394dcd2c838af?version=3.20.1

Есть несколько проблем с этим подходом:

  1. Представление Job.svelte должно в основном сбрасываться, когда вы предоставляете новый идентификатор, и очищать любой предыдущий опросщик, но теперь он супер неудобно с реактивным оператором внизу
  2. Поскольку поллер выполняет асинхронную выборку, может случиться так, что обработчик тайм-аута poller очищается, даже если обработчик уже выполняется. Это приводит к возникновению нескольких циклов опроса (вы можете воспроизвести это, щелкая по списку заданий с произвольными интервалами от 0 до 2 секунд)
  3. Текущий подход не удобен для разработчиков и его легко нарушить. «Ошибка», описанная выше, может быть исправлена ​​путем отслеживания типа ссылки / блокировки, но тогда еще сложнее обернуть голову.

Для этого варианта использования, что является лучшим способом реализовать его (в Svelte)?

Спасибо большое!

Ответы [ 3 ]

1 голос
/ 25 апреля 2020

Представление Job.svelte в основном должно сбрасываться, когда вы предоставляете новый идентификатор и очищаете любой предыдущий опросчик, но теперь это очень неудобно с реактивным оператором внизу

Мне нравится предыдущий ответ уже указывал, что это путь Svelte. Сначала это неудобно, пока вы не поймете, что это очень просто, удобно и элегантно.

В вашем коде я хотел бы улучшить две вещи:

  • избавиться от грязного кэша для каждого идентификатора + одно присваивание значения прогресса; это то, что заставляет ваши поздние выборки отображаться визуально (сам по себе ответ поздней выборки не является ошибкой, однако отображение его вашему пользователю - это ); Я просто переименовал ваш объект кеша в progress и решил отображать progress[id], таким образом, ответ с поздней выборкой будет обновляться в фоновом режиме, но не мешать визуально отображаемой в данный момент работе
  • , вместо этого используйте setInterval кратных setTimeout для периодов c опросов
<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>

См. этот ответ

1 голос
/ 24 апреля 2020

Я думаю, что 1. это просто путь к go на Svelte. Нет ngOnChanges, как в angular.

2. / 3. Я думаю, это не зависит от Svelte. Асинхронные вещи с гонками времени всегда сложны. Такие библиотеки, как rxjs, облегчают эту задачу, но имеют крутую кривую обучения. Пример:

<script>
  import { interval, Subject } from 'rxjs';
  import { switchMap, take, map, startWith, tap } from 'rxjs/operators';

  const cache = {};
  const id$ = new Subject();
  const progress$ = id$.pipe(
    // every time id$ gets a new id, start new interval
    switchMap(id => {
      return interval(1000).pipe(
        // every time the interval emits, do an api call
        switchMap(() => {
          // fake api call
          return interval(200).pipe(
            take(1),
            map(() => id + '::' + Math.random()),
            // store value in cache
            tap(value => cache[id] = value)
          );
        }),
        // start with cached value
        startWith(cache[id]),
      );
    })
  );

  let id = 1;
  function switchPoll() {
    id = id === 2 ? 1 : 2;
    id$.next(id);
  }
</script>

<p>{$progress$}</p>
<button on:click={switchPoll}>Switch</button>
0 голосов
/ 24 апреля 2020

Я бы предложил использовать блоки await от svelte. С ним у вас есть все логи c, необходимые для асинхронной функциональности из коробки, такой как создание экрана загрузки или отлов ошибок. Я изменил ваш REPL с помощью пользовательской функции тайм-аута (сна) для имитации выборки данных с удаленного сервера:

<script>    
    let selectedJob;
    let progress = 0
        function sleep(ms) {
      return new Promise(resolve => setTimeout(resolve, ms));
    }

    const pollProgress = async (id) => {    
        if(progress < 10) {;
      await sleep(300)
            progress += 1
            return pollProgress(id)
        }
        return "Done"
    }   

    function handleClick(id) {
        selectedJob = id
        promise = pollProgress(id);
    }
    let promise
</script>

<style>
    .list {
        background-color: yellow;
        cursor: pointer;
    }

    .details {
        background-color: cyan;
    }
</style>

<div class="list">
  {#each new Array(10).fill().map((_, i) => i) as i}
       <div on:click={() => (handleClick(i))}>
             Job {i}
         </div>
    {/each}
</div>

{#if selectedJob !== undefined}
    <div class="details">
        <h2>Job details</h2>
        <div>
        <p>
        ID: {selectedJob}
    </p>
{#await promise}
    <p>Progress: {progress}</p>
{:then res}
    <p>
        Progress: {res}
    </p>
{:catch error}
    <p style="color: red">{error.message}</p>
{/await}
</div>
    </div>
{/if}

Он будет отображать ход обновления для имитации опроса, пока он выбирает данные и строка Done , которые он получает в результате от функции asyn c, когда завершается.

...