Нажимать URL несколько раз в течение максимум одной минуты в angular

#angular #rxjs

#angular #rxjs

Вопрос:

У меня есть функция в angular, которая возвращает набор данных со статусом «Продолжить» или «завершено». Я хочу продолжать нажимать на вызов до тех пор, пока статус не вернется «завершено», но максимум на одну минуту. Как я могу добиться этого в angular

 public getLeadsResponse(key: any) {
    this._service.getLeadsData(key).subscribe((response: any) => {
        if (response) {
            if (response.payload.status == "running") {
    // here if i repeate this function it will start an infinite loop if status is always "running"
                this.getLeadsResponse(key);
            }
            else if (response.payload.status == "finished") {
                this.items = res.payload.resu<
            }
        }
    })
}
 

Ответ №1:

Вы можете сделать это с помощью expand() :

 import { of, EMPTY, timer } from 'rxjs'; 
import { expand, map, filter, takeUntil } from 'rxjs/operators';

const makeHttpRequest$ = timer(1000).pipe(map(() => Math.random() > 0.9 ? 'finished' : 'continue'));

const source = of(null).pipe(
  expand(value => value === 'finished' ? EMPTY : makeHttpRequest$),
  filter(value => value !== null), // Ignore the first `of(null)` that triggered the chain.
  takeUntil(timer(60 * 1000)),
);

source.subscribe(console.log);
 

Живая демонстрация: https://stackblitz.com/edit/rxjs-8n11jj?devtoolsheight=60

Комментарии:

1. куда я должен поместить свой _service call @martin? в math.random() месте..

2. Извините, если это глупый вопрос, я новичок в rxjs

3. Вместо makeHttpRequest$

4. Вы должны вернуть наблюдаемое expand значение, чтобы оно было там, где вы его разместили

5. @ martin в троичном операторе вы используете EMPY, что я должен поместить туда вместо ПУСТОГО?

Ответ №2:

В дополнение к ответу @martin вы также можете выполнить явную проверку метки времени в течение 1 минуты с помощью timestamp оператора RxJS.

Я использовал RxJS timer для отправки каждых ‘n’ временных единиц и переключения на HTTP-запрос для каждого из них с использованием switchMap оператора.

Попробуйте следующее

 import { timer } from "rxjs";
import { filter, map, timestamp, switchMap } from "rxjs/operators";

public getLeadsResponse(key: any) {
  const now = Date.now();

  const subscription = timer(0, 6000).pipe(  // <-- adjust polling frequency
    switchMap(_ => this._service.getLeadsData(key)),
    timestamp(),
    map((data: { timestamp: number; value: any }) => {
      if (data.timestamp - now < 60000) {               
        return data.value;
      } else {
        subscription.unsubscribe();  // <-- close subscription if 1 min has elapsed
      }
    }),
    filter(response => response.payload.status == "finished")
  ).subscribe({
    next: response => {
      this.items = res.payload.result;
      subscription.unsubscribe();  // <-- close subscription if status is "finished"
    },
    error: error => {
      // handle error
    }
  });
}
 

Ответ №3:

Я думаю, вы можете добавить только тайм-аут к вашему ajax-запросу, который «разорвет» соединение с сервером, если это произойдет. Таким образом, вы не сможете проверить значение результата полезной нагрузки.

Вы можете реализовать желаемое поведение другими способами :

  • сделайте свой серверный процесс асинхронным, чтобы вы могли выполнять ajax-запрос, скажем, каждые 5 секунд, чтобы проверить текущее состояние, и маршрут, по которому вы добираетесь, должен быстро реагировать и просто «проверять статус операции». тогда логика проверки не более 1 минуты будет в вашем интерфейсном приложении
  • откройте соединение с длинным опросом, которое может отправлять несколько сообщений, используя, например, SSE
  • Сделайте то же самое, что и выше, используя websocket.

Во всех случаях реальный дизайн заключается в том, что работа вашего внутреннего сервера должна быть асинхронной, и он может передавать свой текущий статус другому процессу / потоку.

Обратите внимание, что в какой-то момент при разработке API вы заканчиваете тем, что делаете подобные вещи. Добавить некоторую асинхронную обработку в проект не так просто, как выполнять простые длинные запросы и усложнять проект, но у этого есть некоторые преимущества, такие как отсутствие перегрузки серверов и более быстрое реагирование на пользовательские интерфейсы.

Комментарии:

1. правильно. но проблема в том, что у нас нет доступа к серверной части. нам просто нужно иметь дело с API. пожалуйста, любое решение с примером.

2. Мое предложение в основном касается внутренних изменений, которые в вашем случае кажутся невозможными. В случае, если в вашем бэкэнде возможны изменения, вы можете добавить маршрут для «регистрации» задачи для обработки в базе данных, например. затем другой процесс на серверной части сервера часто ищет задачи для продолжения, если таковые имеются, запускает фоновый длительный процесс и обновляет статус задачи в базе данных, чтобы другой маршрут с параметром идентификатора задачи мог возвращать статус задачи в базу данных. Есть много способов реализовать это из scrach, используя системы задач, такие как celery docs.celeryproject.org или даже более сложные системы очередей.