export interface PromiseFunction { (...args: any[]): Promise } export interface DeferredPromise { promise: Promise resolve: (val: T) => void reject: (error: Error) => void } export function debounce(this: any, promiseFunction: PromiseFunction): PromiseFunction { let lastArguments: any[] = null as any let pendingPromise: Promise = null as any let queuedPromises: Array> = [] const executeNextPromise = () => { if (!pendingPromise && queuedPromises.length > 0) { for (let i = 0; i < queuedPromises.length - 1; i++) { queuedPromises[i].reject(new Error("Preempted")) } const currentPromise = queuedPromises[queuedPromises.length - 1] queuedPromises = [] runPromiseFunction(currentPromise, lastArguments) } } const runPromiseFunction = (currentPromise: any, lastArgs: any) => { pendingPromise = promiseFunction.apply(this, lastArgs) lastArguments = null pendingPromise.then((val) => { currentPromise.resolve(val) pendingPromise = null as any executeNextPromise() }, (err) => { currentPromise.reject(err) pendingPromise = null as any executeNextPromise() }) } return function(...args): Promise { // tslint:disable-line only-arrow-functions let resolve: any = null let reject: any = null const promise = new Promise(function() { // tslint:disable-line only-arrow-functions resolve = arguments[0] reject = arguments[1] }) const deferredPromise = { resolve, reject, promise, } lastArguments = args queuedPromises.push(deferredPromise as any) executeNextPromise() return promise } }