欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  科技

不一样的函数防抖和节流

程序员文章站 2022-06-19 15:44:00
防抖和节流浏览器的 resize、scroll、keypress、mousemove 等事件在触发时,会不断地调用绑定在事件上的回调函数,极大地浪费资源,降低前端性能。为了优化体验,需要对这类事件进行调用次数的限制。狂点一个按钮页面滚动入模糊匹配。。。。。。防抖(debounce)在某一次高频触发下,我们只识别一次(可以控制开始触发,还是最后一次触发)详细:假设我们规定500MS触发多次算是高频,只要我们检测到是高频触发了,则在本次频繁操作下(哪怕你操作了10次)也是只触发一次…<...

防抖和节流

浏览器的 resize、scroll、keypress、mousemove 等事件在触发时,会不断地调用绑定在事件上的回调函数,极大地浪费资源,降低前端性能。为了优化体验,需要对这类事件进行调用次数的限制。

  • 狂点一个按钮
  • 页面滚动
  • 入模糊匹配
  • 。。。。。。

防抖(debounce)

在某一次高频触发下,我们只识别一次(可以控制开始触发,还是最后一次触发)
详细:假设我们规定500MS触发多次算是高频,只要我们检测到是高频触发了,则在本次频繁操作下(哪怕你操作了10次)也是只触发一次…

<button id="submit">点击</button>
function () {
  console.log("hello world")
}

上面按钮每一次点击,都会触发打印,如果疯狂点击,那么下面就会疯狂打印,会降低性能。

实际开发1:使用按钮只会,移除事件绑定

<button id="submit">点击</button>
function handle() {
    submit.onclick = null;
    submit.disabled = true;
    console.log('OK');
    setTimeout(() => {
      submit.onclick = handle;
      submit.disabled = false;
    }, 1000);
}
submit.onclick = handle;

实际开发2:使用按钮只会,移除事件绑定

<button id="submit">点击</button>
let flag = false;
submit.onclick = function () {
  if (flag) return;
  flag = true;
  console.log('OK');
  setTimeout(() => {
    // 事情处理完
    flag = false;
  }, 1000);
};

封装一个函数防抖的方法

<button id="submit">点击</button>
function debounce(func, wait, immediate) {
  // 多个参数及传递默认的处理
  if (typeof func !== "function") throw new TypeError("func must be an function!");
  if (typeof wait === "undefined") wait = 500;
  if (typeof wait === "boolean") {
    immediate = wait;
    wait = 500;
  }
  if (typeof immediate !== "boolean") immediate = false;

  // 设定定时器返回值标识
  let timer = null;
  return function proxy(...params) {
    let self = this,
      now = immediate && !timer;

    clearTimeout(timer);
    timer = setTimeout(function () {
      timer = null;
      !immediate ? func.call(self, ...params) : null;
    }, wait);

    // 第一次触发就立即执行
    now ? func.call(self, ...params) : null;
  };
}

function handle(ev) {
  // 具体在点击的时候要处理的业务
  console.log('OK', this, ev);
}
submit.onclick = debounce(handle, true);
// submit.onclick = proxy;  疯狂点击的情况下,proxy会被疯狂执行,我们需要在proxy中根据频率管控handle的执行次数
// submit.onclick = handle; //handle->this:submit  传递一个事件对象

简洁版本的防抖

function myDebounce(fn, interval = 500) {
  let timeout = null;
  return function () {
    clearTimeout(timeout);
    timeout = setTimeout(() => {
      fn.apply(this, arguments);
    }, interval);
  };
}
function doSomething(){
    // onmousemove触发的事件回调函数
}
container.onmousemove = myDebounce(doSomething, 300);

节流(throttle)

在某一次高频触发下,我们不是只识别一次,按照我们设定的间隔时间(自己规定的频率),没到达这个频率都会触发一次
详细:假设我们规定频率是500MS,我们操作了10min,触发的次数=(10601000)/500

比如,滚动页面,触发了多次打印

body {
  height: 3000px;
  overflow-x: hidden;
  background: -webkit-linear-gradient(top left, lightblue, pink, orange);
}
window.onscroll = function () {
  // 默认情况下,页面滚动中:浏览器在最快的反应时间内(4~6MS),就会识别监听一次事件触发,把绑定的方法执行,这样导致方法执行的次数过多,造成不必要的资源浪费
  console.log('OK');
};

封装一个函数节流的方法

body {
  height: 3000px;
  overflow-x: hidden;
  background: -webkit-linear-gradient(top left, lightblue, pink, orange);
}
function throttle(func, wait) {
  if (typeof func !== "function") throw new TypeError("func must be an function!");
  if (typeof wait === "undefined") wait = 500;
  let timer = null,
    previous = 0; //记录上一次操作的时间
  return function proxy(...params) {
    let self = this,
      now = new Date(), //当前这次触发操作的时间
      remaining = wait - (now - previous);
    if (remaining <= 0) {
      // 两次间隔时间超过wait了,直接执行即可
      clearTimeout(timer);
      timer = null;
      previous = now;
      func.call(self, ...params);
    } else if (!timer) {
      // 两次触发的间隔时间没有超过wait,则设置定时器,让其等待remaining这么久之后执行一次「前提:没有设置过定时器」
      timer = setTimeout(function () {
        clearTimeout(timer);
        timer = null;
        previous = new Date();
        func.call(self, ...params);
      }, remaining);
    }
  };
}

function handle() {
  console.log('OK');
}
window.onscroll = throttle(handle, 500);

简洁版本的节流

function myThrottle(fn, interval = 500) {
  let run = true;
  return function () {
    if (!run) return;
    run = false;
    setTimeout(() => {
      fn.apply(this, arguments);
      run = true;
    }, interval);
  };
}

function doSomething(){
    // onmousemove触发的事件回调函数
}
container.onmousemove = myThrottle(doSomething, 300);

本文地址:https://blog.csdn.net/uperficialyu/article/details/111826132

相关标签: 高级前端编程