Необходимость использования оператора share() в конвейере RxJS

#rxjs #multicast

#rxjs #многоадресная рассылка

Вопрос:

Я играю с образцом «индикатора сохранения», который зависит от RxJS.

Вот полный исходный код:

 import { fromEvent, of, merge, empty, concat, defer } from 'rxjs';
import {
  delay,
  map,
  mergeMap,
  tap,
  debounceTime,
  distinctUntilChanged,
  mapTo,
  filter,
  share,
  switchAll
} from 'rxjs/operators';
import { format } from 'date-fns';
​
// track in progress saves
let savesInProgress = 0;
​
// references
const input = document.getElementById('note-input');
const saveIndicator = document.querySelector('.save-indicator');
​
// streams
const keyup$ = fromEvent(input, 'keyup');
​
// fake save request
const saveChanges = value => {
  return of(value).pipe(delay(1500));
};
​
/**
 * Trigger a save when the user stops typing for 200ms
 * After new data has been successfully saved, so a saved
 * and last updated indicator.
 */
const inputToSave$ = keyup$.pipe(
  debounceTime(200),
  map(e => e.target.value),
  distinctUntilChanged(),
  share()//Here!!
);
​
const savesInProgress$ = inputToSave$.pipe(
  mapTo(of('Saving')),
  tap(_ => savesInProgress  )
);
​
const savesCompleted$ = inputToSave$.pipe(
  mergeMap(saveChanges),
  tap(_ => savesInProgress--),
  // ignore if additional saves are in progress
  filter(_ => !savesInProgress),
  mapTo(
    concat(
      // display saved for 2s
      of('Saved!'),
      empty().pipe(delay(2000)),
      // then last updated time, defer for proper time
      defer(() => of(`Last updated: ${format(Date.now(), 'MM/DD/YYYY hh:mm')}`))
    )
  )
);
​
merge(savesInProgress$, savesCompleted$)
  .pipe(
    /*
   If new save comes in when our completion observable is running, we want to switch to it for a status update.
  */
    switchAll()
  )
  .subscribe(status => {
    saveIndicator.innerHTML = status;
  });
  

И ссылка, по которой можно найти исходный код: https://www.learnrxjs.io/learn-rxjs/recipes/save-indicator

Мне интересно, зачем share() здесь нужен оператор многоадресной рассылки. Я попытался удалить его, и поведение приложения не изменилось.

Может кто-нибудь, пожалуйста, объяснить, почему share() здесь требуется оператор?

редактировать: Пожалуйста, также имейте в виду, что существует только одна подписка / subscribe.

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

1. Попробуйте добавить tap(console.log) before share и посмотрите, действительно ли изменилось поведение.

2. Спасибо за комментарий. Какую часть конвейера вы ожидали увидеть измененной? Я пробовал tap перед share : ничего не меняется.

3. комментарий @ritaj, вероятно, соответствовал тому, что вы увидите разницу, проявляющуюся в том, что регистрируется. Хотя вы подписываетесь только один раз в конце, вы можете видеть, что это подписка на merge(savesInProgress$, saveComplete$) , которая подписывается на них обоих. И каждый из них подписывается inputToSave$ , так что в итоге у вас будет 2 подписки на этот поток

4. В данном случае это, вероятно, не имеет большого значения… возможно, это было бы немного эффективнее с помощью share(), поскольку он создаст только одного слушателя, а затем отключит, сопоставит и сравнит один раз, но IMO, это действительно не имеет большого значения в этом примере.

5. Спасибо вам обоим! Я не понял этого в отношении двух подписок.