每天5分钟 - 使用TDD的方式实现节流

315 阅读2分钟

「这是我参与11月更文挑战的第2天,活动详情查看:2021最后一次更文挑战」。

前言

大家好,我是轮子猫。本系列文章将带你使用 TDD 的方式每天花费 5 分钟,完成一个大厂笔试、面试必考手写题目。

  1. 防抖
  2. 节流 ✅
  3. call、apply、bind
  4. EventEmitter
  5. 手动实现 ES5 继承
  6. 手动实现 instanceof
  7. Object.create
  8. new
  9. 浅拷贝和深拷贝
  10. 单例模式
  11. 手动实现 JSONP
  12. 数组去重、扁平、最值
  13. 数组乱序 - 洗牌算法
  14. 函数柯里化
  15. 模拟实现 promise
  16. 基于 Promise 的 ajax 封装
  17. 异步循环打印
  18. 图片懒加载

需求

同样,在实现节流之前,我们先来了解一下节流的定义。节流指的是,每隔 n 秒,只执行一次函数。如果在 n 秒内多次触发函数 ,只有一次生效。 节流和防抖很像,不过,一般来说在 n 秒内连续触发事件,节流只在第一次触发有效。 ​

现在我们来拆解一下需求:

  1. 每隔 n 秒,只执行一次函数:也就是延迟执行函数
  2. 函数在 n 秒被连续触发,只执行第一次触发的函数,忽略其他的触发事件。

实现

现在我们来一步一步实现节流。

需求 1

首先,我们先实现关于延迟执行函数的测试代码

// throttle.test.js
test('should dealy function', function(done) {
  const mockFn = jest.fn();
  const throttledFn = throttle(mockFn, 10);

  throttledFn();
  expect(mockFn.toBeCalledTimes(0);

  setTimeout(function() {
    expect(mockFn).toBeCalledTimes(1);

    done();
  }, 20);
})

运行测试代码

image.png

实现测试代码

// throttle.js
function throttle(fn, n) {
  return function () {
    setTimeout(function () {
      fn();
    }, n);
  };
}

接着,我们继续运行测试代码

image.png

需求 2

现在,我们来实现拆解后的需求 2,测试代码如下

// throttle.test.js
test("should throttle function", function (done) {
  const mockFn = jest.fn((val) => val);
  const throttledFn = throttle(mockFn, 32);
  let result;

  throttledFn("a");
  throttledFn("b");

  expect(mockFn).toBeCalledTimes(0);

  setTimeout(function () {
    result = throttledFn("c");

    expect(mockFn).toBeCalledTimes(1);
    expect(result).toBe("a");

    done();
  }, 64);
});

实现

// throttle.js
function throttle(fn, n) {
  let timer = null;
  let val;

  return function (...args) {
    const context = this;

    if (!timer) {
      timer = setTimeout(function () {
        timer = null;
        val = fn.apply(context, args);
      }, n);
    }

    return val;
  };
}

最后,运行测试代码

image.png

这样,最基本的节流函数就已经成功实现了,收工!~