节流 and 防抖

防抖

防抖:对于短时间内连续触发的事件,防抖的含义就是让某个时间期限内,事件处理函数只执行一次。
例子:
在第一次触发事件时,不立即执行函数,而是给出一个期限值比如 200ms ,然后:

  • 如果在 200ms 内没有再次触发滚动事件,那么就执行函数
  • 如果在 200ms 内再次触发滚动事件,那么当前的计时取消,重新开始计时

如果短时间内大量触发同一事件,只会执行一次函数。用去除定时器的方法。

  1. function debounce(fn, delay) {
  2. let timer = null;
  3. return function () {
  4. if (timer) {
  5. clearTimeout(timer)
  6. timer = setTimeout(fn, delay)
  7. } else {
  8. timer = setTimeout(fn, delay)
  9. }
  10. }
  11. }
  12. function showTop() {
  13. var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
  14. console.log('滚动条位置:' + scrollTop);
  15. }
  16. window.onscroll = debounce(showTop, 1000);

如果在限定时间段内,不断触发滚动事件(比如某个用户闲着无聊,按住滚动不断的拖来拖去),只要不停止触发,理论上就永远不会输出当前距离顶部的距离。

节流

如果短时间内大量触发同一事件,那么在函数执行一次之后,该函数在指定的时间期限内不再工作,直至过了这段时间才重新生效。

  1. function throttle(fn, delay) {
  2. let valid = true;
  3. return function () {
  4. if (!valid) {
  5. return false;
  6. }
  7. valid = false;
  8. setTimeout(() => {
  9. fn()
  10. valid = true;
  11. }, delay)
  12. }
  13. }
  14. function showTop() {
  15. var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
  16. console.log('滚动条位置:' + scrollTop);
  17. }
  18. window.onscroll = throttle(showTop, 1000)

运行以上代码的结果是:

  • 如果一直拖着滚动条进行滚动,那么会以 1s 的时间间隔,持续输出当前位置和顶部的距离。

节流还可以用时间戳实现:

  1. function throttle(fn, delay) {
  2. let previous = 0;
  3. return function() {
  4. let now = Date.now();
  5. let context = this;
  6. let args = arguments;
  7. if (now - previous > delay) {
  8. fn.apply(context, args);
  9. previous = now;
  10. }
  11. }
  12. }

应用场景

  1. 搜索框input事件
  2. 滚动条滚动事件
  3. 页面 resize 事件,常用于需要做页面适配的时候,需要根据最终呈现的页面情况进行 dom 渲染(这种情况一般是使用防抖,因为只需要判断最后一次的变化情况)

    深拷贝 and 浅拷贝

    深拷贝

    1. function deepClone(obj) {
    2. if (typeof obj !== 'object' || obj === null) return obj;
    3. let copy = {};
    4. if (Array.isArray(obj)) {
    5. copy = [];
    6. }
    7. for (const [key, value] of (Array.isArray(obj) ? obj.entries() : Object.entries(obj))) {
    8. copy[key] = deepClone(value);
    9. }
    10. return copy;
    11. }

    浅拷贝

    1. const extend = Object.assign || ((obj, ...args) => {
    2. if (args.length !== 0) {
    3. for(const source of args) {
    4. for(const [key, value] of Object.entries(source)) {
    5. obj[key] = value;
    6. }
    7. }
    8. }
    9. return obj;
    10. })