博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
上海下雨了,不来点函数防抖、节流压压惊?
阅读量:6607 次
发布时间:2019-06-24

本文共 5270 字,大约阅读时间需要 17 分钟。

今年5月份毕业出来找工作的时候听说的函数防抖与节流,拖到现在采取整整的整理了解,之前也看过几篇关于函数节流和防抖的文章,但是作者都没好好检查下代码就把报错的代码发上来,所以今天 特意花点时间自己去好好了解函数防抖、函数节流,也遇到一些小坑,分享给大家,也作为自己的笔记。

首先要搞明白为什么要用函数防抖 函数节流,因为在开发时,有些操作调用函数十分的频繁,比如 resize、scroll、mousemove

我这边用的是mousemove事件做的例子

0//html let span = document.getElementById('span')//js  let num = 0  function mouseover (...args){    console.log('mouseoverz执行了')    num++    this.innerHTML = num   }复制代码

函数防抖 debounce

当你连续触发函数的时候,函数只会被触发一次。主要有以下两种

1.非立即执行版

//非 立即执行版    const debounce = (func,wait,...args)=>{      let timeout;      return function () {        let context = this;        if(timeout) clearTimeout(timeout);        timeout = setTimeout(()=>{          func.apply(context,args);        }, wait)      }    }span.onmouseover = debounce(mouseover,1000,'a','b','c')复制代码

每次经过数字都会产生一个新的计时器,清除旧的计时器,直到你在1秒内不执行这个函数,目标函数才会被调用

在写这个函数的时候也发现了箭头函数和普通函数的一些区别

//setTimeout 回调函数为非箭头函数         const debounce = (func,wait,...args)=>{          let timeout           return function (e){            const context = this            if(timeout) clearTimeout(timeout);            timeout = setTimeout(function(){//setTimeout 返回值是这个额计时器一个唯一标志符                         对于延时函数内部的回调函数的this指向全局对象window              console.log(this)//window 有点意外吧 setTimeout是window的方法所以this指向window              console.log(context)//这个好理解,谁去调用就指向哪个              func.apply(context,args)//apply能够将数组自动转化为参数列表            }, wait)          }        }     //setTimeout 回调函数为箭头函数     const debounce = (func,wait,...args)=>{        let timeout         return function (e){          const context = this          if(timeout) clearTimeout(timeout);          timeout = setTimeout(()=>{//setTimeout 返回值是这个额计时器一个唯一标志符对于                                  延时函数内部的回调函数的this指向全局对象window            console.log(this)//由于这里的函数时箭头函数,箭头函数的this指向的是定义时的this,而不是执行的this,                                    所以这里的this会和context保持一致            console.log(context)            func.apply(context,args)//apply能够将数组自动转化为参数列表          }, wait)        }      }span.onmouseover = debounce(mouseover,1000,'a','b','c')复制代码

2.立即执行版

const debounce = (func,wait,...args)=>{      let timeout;      return function (){        let context = this        if(timeout) clearTimeout(timeout);        if(!timeout) func.apply(context,args);        timeout = setTimeout(()=>{          timeout = null        }, wait)      }    }复制代码

每次经过数字都会产生一个新的计时器,清除旧的计时器,如果timeout为null 那么就会立即执行目标函数 必须间隔1秒后划过数字,函数才能再次被触发

结合版

// 结合版    const debounce = (func,wait,blo,...args) => {      let timeout;      return function () {        let context = this;        if(timeout) clearTimeout(timeout);        if(blo){//立刻执行版          if(!timeout) func.apply(context,args)          timeout = setTimeout(()=>{            timeout = null          }, wait)        }else{//非 立刻执行版          timeout = setTimeout(()=>{            func.apply(context,args)          }, wait)        }      }    }    span.onmouseover = debounce(mouseover,1000,false,'a','b','c')复制代码

2.函数节流 throttle

函数节流:你连续触发某个函数,你可以控制这个函数多久触发一次 ,而函数防抖实际上是你连续触发某个函数,最终只会触发一次,你需要停止触发,过一段时间再去触发,才能再次触发成功

第一种:时间戳版

// 时间戳版  //连续触发时 第一次会立即执行,之后秒执行一次    const throttle = (func,wait,...args) => {      let previous = 0;      return function () {        let context = this;        let now = Date.now()        if(now - previous > wait){          func.apply(context,args)          previous = now        }      }    }复制代码

这里应该很清楚,不需要解释

第二种:计时器版

// 计时器版  //连续触发时 第一次不会立即执行,一秒后秒执行一次 所以会出现你停止不滑动后,数字最后跳了一次    const throttle = (func,wait,...args)=>{      let timeout;      return function () {        let context = this;        if(!timeout){          timeout = setTimeout(()=>{            timeout = null;            func.apply(context,args)          },wait)        }      }    }复制代码

节流结合版

这是我一开始写的,其实是有问题的,你能发现吗

// 节流的结合版    const throttle = (func,wait,type,...args) => {      console.log(type === 1)      if(type === 1){//时间戳版        let previous = 0//      }else if(type === 2){//定时器版        let timeout      }      console.log(timeout)      return function () {//时间戳版        let context = this        if(type === 1){          let now = Date.now();          if(now - previous > wait){            func.apply(context,args)            previous = now          }        }        if(type === 2){//定时器版          if(!timeout){            timeout = setTimeout(()=>{              timeout = null;              func.apply(context, args)            }, wait)          }        }      }    }    span.onmouseover = throttle(mouseover,1000,1,'a','b','c')复制代码

看了报错,才找到的原因

// 节流的结合版    const throttle = (func,wait,type,...args) => {      console.log(type === 1)      if(type === 1){//时间戳版        var previous = 0//这里不能用let 因为有块级作用域,return出去function不能访问,所以要用var      }else if(type === 2){//定时器版        var timeout      }      console.log(timeout)      return function () {//时间戳版        let context = this        if(type === 1){          let now = Date.now();          if(now - previous > wait){            func.apply(context,args)            previous = now          }        }        if(type === 2){//定时器版          if(!timeout){            timeout = setTimeout(()=>{              timeout = null;              func.apply(context, args)            }, wait)          }        }      }    }    span.onmouseover = throttle(mouseover,1000,1,'a','b','c')复制代码

转载地址:http://lkdso.baihongyu.com/

你可能感兴趣的文章
ansible模块批量管理
查看>>
redis命令 - GET
查看>>
httpd.conf的基本设置
查看>>
RHEL/Centos7新功能
查看>>
第一部分 思科九年 一(1)
查看>>
DBA日常工作职责
查看>>
Redis的持久化
查看>>
linux安装NFS服务器学习
查看>>
Planner .NET日历日程控件能给你的应用程序提供多种日历日程功能
查看>>
我的友情链接
查看>>
Linux压力测试
查看>>
JAVA中的线程机制(二)
查看>>
nginx安装与配置2(转载)
查看>>
Linux下Mongodb安装和启动配置
查看>>
2015 成长计划
查看>>
沈阳一饭店凌晨爆燃,燃气报警器时刻预防
查看>>
Redis 与 数据库处理数据的两种模式
查看>>
VUE2中axios的使用方法
查看>>
CS 229 notes Supervised Learning
查看>>
2018.10.27-dtoj-3996-Lesson5!(johnny)
查看>>