在 JavaScript 中实现防抖 Promise

Beginner

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

简介

在本实验中,我们将探索如何在 JavaScript 中创建一个返回 Promise 的防抖函数。我们将学习如何延迟调用一个函数,直到指定的时间过去,以及如何处理在此期间返回的多个 Promise,以确保它们都返回相同的数据。在本实验结束时,你将对如何在 JavaScript 项目中使用 Promise 实现防抖有深入的理解。

这是一个实验(Guided Lab),提供逐步指导来帮助你学习和实践。请仔细按照说明完成每个步骤,获得实际操作经验。根据历史数据,这是一个 初级 级别的实验,完成率为 100%。获得了学习者 100% 的好评率。

防抖 Promise

要创建一个返回 Promise 的防抖函数,该函数会延迟调用提供的函数,直到自上次调用以来至少经过了 ms 毫秒,请按以下步骤操作:

  1. 每次调用防抖函数时,使用 clearTimeout() 清除当前挂起的超时,然后使用 setTimeout() 创建一个新的超时,该超时会延迟调用函数,直到至少经过了 ms 毫秒。
  2. 使用 Function.prototype.apply()this 上下文应用于函数并提供必要的参数。
  3. 创建一个新的 Promise,并将其 resolvereject 回调添加到挂起的 Promise 堆栈中。
  4. 当调用 setTimeout() 时,复制当前堆栈(因为在提供的函数调用与其解析之间它可能会改变),清除它并调用提供的函数。
  5. 当提供的函数解析/拒绝时,使用返回的数据解析/拒绝堆栈中的所有 Promise(在调用函数时复制)。
  6. 省略第二个参数 ms,将超时设置为默认的 0 毫秒。

以下是 debouncePromise() 函数的代码:

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 });
    });
};

以下是如何使用 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);
// 两次都会输出 ['resolved', 'bar']

总结

恭喜你!你已经完成了防抖 Promise 实验。你可以在 LabEx 中练习更多实验来提升你的技能。