Introduction
In this lab, we will explore how to create a debounced function that returns a promise in JavaScript. We will learn how to delay invoking a function until a specified time has elapsed, and how to handle multiple promises returned during this time to ensure they all return the same data. By the end of this lab, you will have a solid understanding of how to implement debouncing with promises in your JavaScript projects.
Debounce Promise
To create a debounced function that returns a promise, delaying invoking the provided function until at least ms milliseconds have elapsed since the last time it was invoked, use the following steps:
- Every time the debounced function is invoked, clear the current pending timeout with
clearTimeout(), then usesetTimeout()to create a new timeout that delays invoking the function until at leastmsmilliseconds has elapsed. - Use
Function.prototype.apply()to apply thethiscontext to the function and provide the necessary arguments. - Create a new
Promiseand add itsresolveandrejectcallbacks to thependingpromises stack. - When
setTimeout()is called, copy the current stack (as it can change between the provided function call and its resolution), clear it and call the provided function. - When the provided function resolves/rejects, resolve/reject all promises in the stack (copied when the function was called) with the returned data.
- Omit the second argument,
ms, to set the timeout at a default of0ms.
Here's the code for the debouncePromise() function:
const debouncePromise = (fn, ms = 0) => {
let timeoutId;
const pending = [];
return (...args) =>
new Promise((res, rej) => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
const currentPending = [...pending];
pending.length = 0;
Promise.resolve(fn.apply(this, args)).then(
(data) => {
currentPending.forEach(({ resolve }) => resolve(data));
},
(error) => {
currentPending.forEach(({ reject }) => reject(error));
}
);
}, ms);
pending.push({ resolve: res, reject: rej });
});
};
Here's an example of how to use debouncePromise():
const fn = (arg) =>
new Promise((resolve) => {
setTimeout(resolve, 1000, ["resolved", arg]);
});
const debounced = debouncePromise(fn, 200);
debounced("foo").then(console.log);
debounced("bar").then(console.log);
// Will log ['resolved', 'bar'] both times
Summary
Congratulations! You have completed the Debounce Promise lab. You can practice more labs in LabEx to improve your skills.