Функция переноса RxJS в наблюдаемом

#rxjs

Вопрос:

У меня есть вопрос, как вы обертываете обычный код синхронизации внутри наблюдаемого. Давайте возьмем этот пример:

 let isCalling = false;

function makeHttpCall(url) {
  isCalling = true;

  return rxJsFetch(url).pipe(tap(() => (isCalling = false)));
}
 

Проблема с этой функцией заключается в том, что isCalling флаг будет установлен независимо от того, подписывается кто-то или нет. Я этого не хочу (потому что он еще не звонит). Чтобы бороться с этим, я обычно делаю что-то вроде:

 let isCalling = false;

function makeHttpCallWrapped(url) {
  return of(null).pipe(
    mergeMap(() => {
      isCalling = true;

      return rxJsFetch(url).pipe(tap(() => (isCalling = false)));
    }),
  );
}
 

И это работает, isCalling устанавливается только после подписки.


Проблема с этим кодом заключается в том, что он не очень элегантен и не понятен для тех, кто начинает с RxJS. Мой вопрос к вам таков: как вы с этим справляетесь? Есть ли в RxJS что-то, о чем я не знаю, что справляется с этим более изящно?

Ответ №1:

Оператор отсрочки RxJS

Отсрочка позволяет создать наблюдаемый при подписке. Это в точности более чистая версия того, что вы уже делаете.

 let isCalling = false;

function makeHttpCall(url) {
  return defer(() => {
    isCalling = true;

    return rxJsFetch(url).pipe(tap(() => (isCalling = false)));
  });
}
 

Ответ №2:

Чтобы сделать это более изящным, я создаю вспомогательный метод fromFunction :

 import { of } from 'rxjs';
import { mergeMap } from 'rxjs/operators';
import { SubscribableOrPromise } from 'rxjs/src/internal/types';

export function fromFunction<T>(func: () => SubscribableOrPromise<T>) {
  return of(undefined).pipe(mergeMap(func));
}
 

А затем используйте его, как:

 let isCalling = false;

function makeHttpCallWrapped(url) {
  return fromFunction(() => {
    isCalling = true;

    return rxJsFetch(url).pipe(tap(() => (isCalling = false)));
  });
}
 

Я вроде как чувствую, from что тоже должен принимать такой вклад.