Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support AbortController #14

Open
kripod opened this issue Jan 14, 2021 · 5 comments
Open

Support AbortController #14

kripod opened this issue Jan 14, 2021 · 5 comments

Comments

@kripod
Copy link

kripod commented Jan 14, 2021

Thank you for this awesome solution for debouncing Promises!

How should this library be used together with p-cancelable?

@sindresorhus
Copy link
Owner

Browsers and Node.js now support AbortController, so maybe we could support that somehow.

@kripod
Copy link
Author

kripod commented Jan 14, 2021

Sounds great if native support for that could be added! 🙌

Until then, do you have any idea about how to debounce Promises with cancelation functionality?

I would like to create debouncers with multiple intervals (e.g. 1000ms, 400ms, 0ms) for the same Promise. Once any of them is called (e.g. the one with 400ms debouncing), all the other debouncers are canceled.

@kripod
Copy link
Author

kripod commented Jan 14, 2021

After long hours of trying, I coudln’t find a way to make pDebounce()-ed callbacks cancelable from the outside. @sindresorhus I would appreciate your help guiding through this process.

@kripod
Copy link
Author

kripod commented Jan 14, 2021

I just came up with a barebones solution by combining this library’s code with p-cancelable’s:

export type Cancelable = {
	cancel: (reason?: unknown) => void;
};

export class CancelError extends Error {
	constructor(reason?: string) {
		super(reason || "Promise was canceled");
		this.name = "CancelError";
	}
}

export function debouncePromise<T, P extends unknown[]>(
	callback: (...args: P) => T,
	msDelay: number,
) {
	let timeoutId = 0;
	let resolves: Array<(value: T | PromiseLike<T>) => void> = [];
	let rejects: Array<(reason?: unknown) => void> = [];

	function reset() {
		timeoutId = 0;
		resolves = [];
		rejects = [];
	}

	function cancelableCallback(...args: P) {
		return new Promise<T>((currentResolve, currentReject) => {
			window.clearTimeout(timeoutId);
			timeoutId = window.setTimeout(() => {
				const result = callback(...args);
				resolves.forEach((resolve) => {
					resolve(result);
				});
				reset();
			}, msDelay);

			resolves.push(currentResolve);
			rejects.push(currentReject);
		});
	}

	cancelableCallback.cancel = (reason: unknown = new CancelError()) => {
		window.clearTimeout(timeoutId);
		rejects.forEach((reject) => {
			reject(reason);
		});
		reset();
	};

	return cancelableCallback;
}

I would love to see similar functionality baked into p-debounce.

@sindresorhus sindresorhus changed the title Cancelability Support AbortController Jan 17, 2021
@rinogo
Copy link

rinogo commented Feb 10, 2022

Being able to cancel a debounced promise would be very useful! At the moment, we're stuck with using a flag to "skip" the related functionality once the "canceled" debounced call executes. It works, but it feels messy and brittle.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants