#javascript #angularjs #typescript #rxjs
#javascript #angularjs #typescript #rxjs
Вопрос:
Итак, у меня есть функция, подобная приведенной ниже
showLoader = () => <T>(source: Observable<T>) => {
LoaderService.loadPage.next(true);
return source.pipe(
finalize(() => {
LoaderService.loadPage.next(false);
})
);
};
И затем я использую его при выполнении HTTP-вызовов, как показано ниже
return this.http.get(url).pipe(showLoader())
Но, допустим, я сталкиваюсь со сценарием, в котором мне нужен загрузчик или любой наблюдаемый объект, если на то пошло, на основе условия; что-то вроде приведенного ниже
const loader : boolean = false
return this.http.get(url).pipe(concat(...), loader ? showLoader() : of(values))
Я попытался использовать iif
оператор, как показано ниже
const loader : boolean = false
return this.http.get(url).pipe(concat(...), mergeMap(v => iif(() => loader, showLoader(), of(v))))
и получил следующую ошибку
TS2345: аргумент типа ‘(источник: Observable) => Observable’ не может быть присвоен параметру типа ‘SubscribableOrPromise<{}>’.
Может ли кто-нибудь помочь мне понять, где я ошибаюсь, и как это исправить
Ответ №1:
вы могли бы сделать это так:
showLoader = (show: boolean = true) => <T>(source: Observable<T>) => {
if (!show) { // just go straight to source
return source;
}
return defer(() => { // defer makes sure you don't show the loader till actually subscribed
LoaderService.loadPage.next(true);
return source.pipe(
finalize(() => {
LoaderService.loadPage.next(false);
})
)
})
};
используйте:
return this.http.get(url).pipe(showLoader(false))
но то, как вы, похоже, статически получаете доступ LoaderService
, пахнет проблемами дизайна и ошибками в вашем будущем. К вашему сведению.
Комментарии:
1. Это на самом деле лучше, чем мой ответ
2. @bryan60 loaderService использует DI и вводится в конструктор. Или если вы предлагаете использовать Httpinterceptor для этого? Если это не проблема, можете ли вы рассказать мне о проблеме дизайна?
3. Проблема с дизайном заключается в том, что у вас, похоже, есть эта функция, использующая статические методы LoaderService. Вы не должны использовать статические методы. Они вызовут проблемы, поскольку вы работаете вне рамок DI, делая это.
4. Большое вам спасибо @bryan60. Это было прямо перед моими глазами, и я не мог заметить. Будут внесены изменения 🙂
Ответ №2:
Я бы предложил что-то вроде следующего:
const startWithTap = (callback: () => void) =>
<T>(source: Observable<T>) => of({}).pipe(
startWith(callback),
switchMap(() => source)
);
const showLoader = () => <T>(source: Observable<T>) => concat(
iif(
() => loader,
source.pipe(
startWithTap(() => LoaderService.loadPage.next(true)),
finalize(() => {
LoaderService.loadPage.next(false);
})
),
EMPTY
), source);
return this.http.get(url).pipe(
showLoader()
);
Комментарии:
1. Мы использовали функцию showLoader во многих местах, и, следовательно, нам нужно будет менять все каналы для передачи исходного кода. есть ли способ передать источник явно?
2. вы должны использовать
defer
вместо этойstartWithTap
функции.3. Спасибо @GogaKoreli за помощь