Debouncing Promises in JavaScript

JavaScriptJavaScriptBeginner
Practice Now

This tutorial is from open-source community. Access the source code

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.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL javascript(("`JavaScript`")) -.-> javascript/BasicConceptsGroup(["`Basic Concepts`"]) javascript(("`JavaScript`")) -.-> javascript/AdvancedConceptsGroup(["`Advanced Concepts`"]) javascript(("`JavaScript`")) -.-> javascript/ToolsandEnvironmentGroup(["`Tools and Environment`"]) javascript/BasicConceptsGroup -.-> javascript/variables("`Variables`") javascript/BasicConceptsGroup -.-> javascript/data_types("`Data Types`") javascript/BasicConceptsGroup -.-> javascript/arith_ops("`Arithmetic Operators`") javascript/BasicConceptsGroup -.-> javascript/comp_ops("`Comparison Operators`") javascript/BasicConceptsGroup -.-> javascript/obj_manip("`Object Manipulation`") javascript/AdvancedConceptsGroup -.-> javascript/async_prog("`Asynchronous Programming`") javascript/AdvancedConceptsGroup -.-> javascript/destr_assign("`Destructuring Assignment`") javascript/AdvancedConceptsGroup -.-> javascript/spread_rest("`Spread and Rest Operators`") javascript/ToolsandEnvironmentGroup -.-> javascript/debugging("`Debugging`") subgraph Lab Skills javascript/variables -.-> lab-28257{{"`Debouncing Promises in JavaScript`"}} javascript/data_types -.-> lab-28257{{"`Debouncing Promises in JavaScript`"}} javascript/arith_ops -.-> lab-28257{{"`Debouncing Promises in JavaScript`"}} javascript/comp_ops -.-> lab-28257{{"`Debouncing Promises in JavaScript`"}} javascript/obj_manip -.-> lab-28257{{"`Debouncing Promises in JavaScript`"}} javascript/async_prog -.-> lab-28257{{"`Debouncing Promises in JavaScript`"}} javascript/destr_assign -.-> lab-28257{{"`Debouncing Promises in JavaScript`"}} javascript/spread_rest -.-> lab-28257{{"`Debouncing Promises in JavaScript`"}} javascript/debugging -.-> lab-28257{{"`Debouncing Promises in JavaScript`"}} end

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:

  1. Every time the debounced function is invoked, clear the current pending timeout with clearTimeout(), then use setTimeout() to create a new timeout that delays invoking the function until at least ms milliseconds has elapsed.
  2. Use Function.prototype.apply() to apply the this context to the function and provide the necessary arguments.
  3. Create a new Promise and add its resolve and reject callbacks to the pending promises stack.
  4. 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.
  5. When the provided function resolves/rejects, resolve/reject all promises in the stack (copied when the function was called) with the returned data.
  6. Omit the second argument, ms, to set the timeout at a default of 0 ms.

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.

Other JavaScript Tutorials you may like