Вот моя попытка:
const urlArr = Array.from({ length: 10 }, (_, idx) => 'url/' + idx);
let idx = 0;
const urlEmitter = new Subject();
const url$ = urlEmitter.asObservable();
const stopEmitter = new Subject();
const stopValues$ = stopEmitter.asObservable();
const start$ = fromEvent(start, 'click');
start$.pipe(take(1)).subscribe(() => (stopEmitter.next(false), urlEmitter.next(urlArr[idx++]))); // Start emitting valeus
const stopSubscription = fromEvent(stop, 'click').pipe(mapTo(true)).subscribe(stopEmitter);
const shouldContinue$ = stopValues$.pipe(map(shouldStop => !shouldStop));
const subsequentStartClicks$ = start$.pipe(
skip(1), // Skip the first time the `start` button is clicked
observeOn(asyncScheduler), // Make sure it emits after the buffer has been initialized
tap(() => stopEmitter.next(false)), // shouldContinue$ will emit `true`
);
const downloadedUrls$ = url$.pipe(
mergeMap(url => of(url).pipe(delay(idx * 500))), // Simulate a file downloading
combineLatest(shouldContinue$), // Make sure it acts according to `shouldContinue$`
filter(([_, shouldContinue]) => shouldContinue),
map(([v]) => v),
tap((v) => console.warn(v)), // Debugging purposes...
// Because of `combineLatest`
// If you click `start` and wait some time, then you click `stop`
// then you click again `start`, you might get the last value added to the array
// this is because `shouldContinue$` emitted a new value
// So you want to make sure you won't get the same value multiple times
distinctUntilChanged(),
tap(() => urlEmitter.next(urlArr[idx++])),
bufferToggle(
start$,
() => stopValues$.pipe(filter(v => !!v)),
)
);
merge(
subsequentStartClicks$.pipe(mapTo(false)), // Might not be interested in click events
downloadedUrls$
)
.pipe(filter(v => !!v))
.subscribe(console.log);
Я был вдохновлен диаграммой bufferToggle
.
Моя идея состояла в том, чтобы следовать тому же подходу, с исключение: значения должны передаваться только тогда, когда поток start$
излучается, и должны останавливаться, когда stop$
сделал.
----X--X----------------------------------> urls$
-Y----------------------------------------> start$
-----------Z------------------------------> end$
-----------[X, X]-------------------------------> urls$
Каждый раз, когда нажимается кнопка stop
, значение true
вставляется в поток stopValues$
. shouldContinue$
определяет, должен ли поток url$
продолжать выдавать значения или нет, в зависимости от stopValues$
.
StackBlitz .