Продолжайте проверять: Angular Observable из Promise

#angular #rxjs #observable #angular-promise

#angular #rxjs #наблюдаемый #angular-обещание

Вопрос:

Я разрабатываю приложение angular, которое подключается к принтеру. У принтера есть своя собственная служба состояния, которая является promise, и она отвечает состоянием принтера. В моем приложении angular мне нужна функциональность, при которой мне нужно постоянно проверять состояние принтера в фоновом режиме. Для этого я пытаюсь использовать функцию observable и subscribe, которая работает не так, как ожидалось.

В моем компоненте PrinterService.ts я определил функцию как:

 getStatus() {
  return from(cordova.xyz.getPrinterStatus()); // getPrinterStatus() is a promise
}
  

И я использую эту функцию в моем HomePage.ts как:

 this.printerService.getStatus().subscribe( (res) => {
  console.log("Printer Status", res);
}
  

Проблема здесь в том, что я получаю ответ о состоянии, но только один раз. Например, если мой принтер включен, он выдаст мне статус «включено», но он просто печатает внутри консоли как один раз. Но когда через 2-3 минуты, если я выключу принтер, он должен выдать мне статус «выключен». Как мне заставить это работать таким образом, чтобы мои службы GetStatus () автоматически искали состояние принтера? Любая помощь приветствуется. Спасибо.

Ответ №1:

Вам нужно будет провести опрос, поскольку обещание выполняется только один раз, используйте таймер

 const { timer, of } = rxjs;
const { switchMap, distinctUntilChanged } = rxjs.operators;

const printerService = {
  getStatus: () => of((Math.random() < .5) ? 'off' : 'on')
}

timer(0, 500).pipe(
  switchMap(_ => printerService.getStatus()),
  distinctUntilChanged()
).subscribe(res => {
  console.log("Printer Status", res);
});  
 <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.6.2/rxjs.umd.min.js"></script>  

distinctUntilChanged будет означать, что observable выдается только при изменении статуса, а не при каждом опросе.

 const { timer, of } = rxjs;
const { switchMap, scan, distinctUntilChanged } = rxjs.operators;

const printerService = {
  getStatus: () => of({ status: (Math.random() < .5) ? 'off' : 'on' })
}

timer(0, 500).pipe(
  switchMap(_ => printerService.getStatus()),
  scan((previous, current) => current.status === previous.status ? previous : current),
  distinctUntilChanged()
).subscribe(res => {
  console.log("Printer Status", res);
});  
 <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.6.2/rxjs.umd.min.js"></script>  

Вы можете использовать scan для отправки предыдущего объекта, если он имеет тот же статус, это означает, что distinctUntilChanged получает тот же объект, поэтому вы отправляете только при изменении статуса.

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

1. будет ли distinctUntilChanged () работать, если мой GetStatus () преобразуется в объект json в случае состояния on и отклоняет строку ошибки в случае отключения ststus?

2. Нет, если это ссылочный объект, но если вы поместите туда map, чтобы сделать его объектом значения, таким как строка, включенным или выключенным, это сработает. Если вам нужно, чтобы переданное значение было объектом, вы могли бы использовать сканирование.

3. Проблема здесь в том, что мой код не идентифицирует текущий.status и предыдущий.status внутри метода scan(). Мой метод GetStatus (): 1. Преобразуется в объект {подключение: 1, coverOpen: 0, errorStatus: 0, isPrintable: true, онлайн: 1, бумага: 0, подача бумаги: 0}, если принтер подключен. 2. Отклоняет строку «Ошибка 0x00013: принтер не подключен», если мой принтер не подключен. Я пытался использовать previous.online и current.online, но scan () выдает ошибку «Свойство ‘online’ не существует для типа ‘unknown'».

4. сканирование похоже на функцию уменьшения, я уменьшаю поток либо до нового значения, либо до предыдущего значения. Вам нужно добавить функцию map перед сканированием, которая преобразует результат GetStatus в то, что является объектом, который вам нужен для этой ситуации. Если ваша функция map возвращает строку ‘online’ или ‘offline’, вам даже не понадобится сканирование, поскольку у вас есть объект value, который будет отфильтрован distinctUntilChanged

5. Это сработало. Еще один вопрос: Вы знаете, как я могу отменить эту подписку, если я вообще не получаю никакого ответа от GetStatus () ???