sanity-plugin-media
Version:
This version of `sanity-plugin-media` is for Sanity Studio V3.
56 lines (48 loc) • 1.82 kB
text/typescript
// Takes a observable-returning function and returns a new function that limits on the number of
// concurrent observables.
import {first, mergeMap} from 'rxjs/operators'
import {Subject, Subscription, Observable, from} from 'rxjs'
const DEFAULT_CONCURRENCY = 4
function remove<T>(array: Array<T>, item: T): Array<T> {
const index = array.indexOf(item)
if (index > -1) {
array.splice(index, 1)
}
return array
}
export const createThrottler = (concurrency: number = DEFAULT_CONCURRENCY) => {
const currentSubscriptions: Array<Subscription> = []
const pendingObservables: Array<Observable<any>> = []
const ready$ = new Subject()
function request(observable: Observable<any>): Observable<any> {
return new Observable(observer => {
if (currentSubscriptions.length >= concurrency) {
return scheduleAndWait$(observable)
.pipe(mergeMap(request)) //
.subscribe(observer)
}
const subscription = observable.subscribe(observer)
currentSubscriptions.push(subscription)
return () => {
remove(currentSubscriptions, subscription)
remove(pendingObservables, observable)
subscription.unsubscribe()
while (pendingObservables.length > 0 && currentSubscriptions.length < concurrency) {
ready$.next(pendingObservables.shift())
}
}
})
}
function scheduleAndWait$(observable: Observable<any>): Observable<any> {
pendingObservables.push(observable)
return ready$.asObservable().pipe(first(obs => obs === observable))
}
return request
}
export const withMaxConcurrency = (
func: (...args: any[]) => Observable<any>,
concurrency: number = DEFAULT_CONCURRENCY
) => {
const throttler = createThrottler(concurrency)
return (...args: Array<any>) => from(throttler(func(...args)))
}