Массив фильтров, наблюдаемый обещанием

У меня есть

  • Массив объектов
  • Функция permission(obj): Promise<boolean>

Как я могу отфильтровать этот массив по обещанию?

Я перепробовал множество вещей, и самый близкий мне был

of(arr).pipe(
  switchMap(items =>
    from(items)
     .pipe(
       mergeMap(item =>
         fromPromise(permission(item)).pipe(
           map(shown => ({show, item})),
           filter(data => data.shown),
           map(data => data.item)
         )
       ))
     ));

Но это только кажется слишком сложным.

Я надеялся, что смогу сделать это более просто, как of(arr).pipe(filterByPromise(permission)), но не могу понять, как.

Я сделал Stackblitz https://stackblitz.com/edit/rxjs-g1u8yk

Код StackBlitz

import { of } from 'rxjs'; 
import { map, filter } from 'rxjs/operators';

// Mocked 3rd party function
function visible(obj): Promise<boolean> {
  return new Promise(resolve => {
    const shouldShow = obj.shouldShow < 30;
    resolve(shouldShow);
  });
}

const arr = [{
  shouldShow: 39,
  data1: 'abc',
  data2: 'bcd'
}, {
  shouldShow: 22,
  data1: 'cde',
  data2: 'def'
}];

of(arr).pipe(
  filter(obj => visible(obj))
).subscribe(result => console.log(result));

1 ответ

Решение

Дж. Б. Низет предложил хорошее решение, но было бы лучше использовать concatMap, если заказ товара имеет значение. Здесь разница между concatMap а также mergeMap объясняется

from(arr).pipe(
  concatMap(element => from(visible(element)).pipe(
    filter(show => show),
    map(() => element)
  ))
).subscribe(console.log);

Другой способ - преобразовать и сжать массив, как это. Но решение о более элегантном я думаю.

zip(...arr.map(obj => from(visible(obj)))).pipe(
  map(visible => arr.filter((item, i) => visible[i]))
).subscribe(console.log);

Вот рабочий пример обоих решений.

Другие вопросы по тегам