IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 防抖与节流(技能吟唱与平A僵直) -> 正文阅读

[JavaScript知识库]防抖与节流(技能吟唱与平A僵直)

写在前面

最近开始在掘金更新文章了!因为掘金上面的文章质量会更高,所以希望能够通过在掘金上面写文章来进一步提高自己的文章水平!

掘金地址
如果你也用掘金,欢迎互关,一起交流技术!


防抖节流是前端优化中的两个点啦!

这两个名词乍一看还是有些让人一头雾水的!

今天就类比游戏中的法术吟唱平A僵直来向大家介绍一下防抖与节流


希望这种类比游戏的介绍方式能够获得大家的认可!

防抖

生活中防抖的例子

  • 酒店的自动开关门
    • 感应到人自动开门,5s后自动关闭
    • 如果5s的倒计时里有人来,那么这个5s重新开始计时

类比技能吟唱

  • 我们知道释放一个法术(魔法)是需要吟唱时间的
    • 比如死歌的R
    • 比如波比的R
  • 假设我们的技能没有CD
    • 那么在技能还没有吟唱完的时候再一次使用技能会打断第一次施法重新开始施法
    • 在上次技能没释放的时候释放下一次技能,第一次施法被打断是很好理解的吧
    • 重新施法,重新开始吟唱也是很好理解的吧

js中的防抖

  • 如键盘输入等
    就和上面两个例子中提到的一样。

按照这个思路写出来就可以了,也不用死记硬背的!

主要是用到了三点

  • addEventListener
  • setTimeout
  • clearTimeout

基础的html代码如下

    const button = document.querySelector('#input')
    function input () {
      console.log('input!');
    }
    function debounce (fn,delay) {
      // Todo: 完成防抖
    }
    button.addEventListener('click', debounce(input,1000))
  • 因为防抖需要知道延时时间和完成的事件,所以防抖有两个参数

1.使用高阶函数,避免添加响应的时候触发函数

  • 我们一步一步来,如果没有使用高阶函数而是直接调用函数,如下图,会在添加响应的时候触发fn()
    function debounce (fn,delay) {
      fn()
    }

  • 所以我们先改为高阶函数解决这个bug
    function debounce (fn,delay) {
      return function () {
        fn()
      }
    }

2.使用setTimeout完成延时执行,clearTimeout来控制刷新延时

2.1我们为什么要把timer定义在函数外面?

  • 为了形成闭包,这样在函数内部才能保证clearTimeout掉timer
    function debounce (fn, delay) {
      let timer
      return function () {
        clearTimeout(timer)
        timer = setTimeout(function () {
          fn()
        }, delay)
      }
    }

3.并不是万事大吉,注意this指针的改变

  • 我们在函数里面log一下this指针
    const button = document.querySelector('#input')
    function input () {
      console.log('input!');
      console.log(this);
    }
    function debounce (fn, delay) {
      let timer
      return function () {
        clearTimeout(timer)
        timer = setTimeout(function () {
          fn()
        }, delay)
      }
    }
    button.addEventListener('click', debounce(input, 300))

在这里插入图片描述


  • 结果函数内部的this指针变成了window,这是肯定不行的

3.1我们用context保存this指针,args保存添加的参数,用apply来改变this指针的指向

 function debounce (fn, delay) {
      let timer
      return function () {
        let context = this
        let args=arguments
        clearTimeout(timer)
        timer = setTimeout(function () {
          fn.apply(context,args)
        }, delay)
      }
    }

在这里插入图片描述


  • 成功得到input的this指针

4.return的function不可以使用匿名函数

其实我们是可以用匿名函数来简化上面的代码的,但是只能简化setTimeout里面的函数

  • 我们需要拿到function里面的context上下文
  • 因为匿名函数没有this指针,所以return的函数写成匿名函数会出错,代码如下
 function debounce (fn, delay) {
      let timer
      return () => {
        let context = this
        let args=arguments
        clearTimeout(timer)
        timer = setTimeout(() => {
          fn.apply(context,args)
        }, delay)
      }
 }

这种写法,this指针会指向window

最终代码

   function debounce (fn, delay) {
      let timer
      return function () {
        let context = this
        let args = arguments
        clearTimeout(timer)
        timer = setTimeout(() => {
          fn.apply(context, args)
        }, delay)
      }
   }

节流

生活中节流的例子

  • 鲸鱼到水面换气
    • 鲸鱼是哺乳动物,所以需要每隔一段时间到水面换气
    • 不一直在水面,因为还需要下潜保持皮肤的水分,这就和节约资源类似
    • 鲸鱼呷一口气,这口气能支撑1个小时,那鲸鱼就下潜了,1小时后再来换气
    • 这就是节流

类比平A僵直

  • 同学们应该都打过王者荣耀吧,是不是有同学拆塔的时候疯狂按攻击键?
  • 有用吗?
    • 没有用,你的攻击次数由你的攻击速度(攻击间隔时长)决定
    • 就是在上一次攻击指令完成前,是没有办法进行下一次攻击指令的
    • 平A的僵直就是节流

js中的节流

  • 如滚动监听
    在上面防抖基础上,节流的介绍就不再那么啰嗦,我们直接开始编写节流的代码

1.使用定时器的思想来完成

1.1根据思路写出基础代码

  • 1.同样是高阶函数
  • 2.同样要操作timertimer闭包
  • 3.如果上一次还没延时没结束,就啥也不做(判断timer是否存在即可)。完成节流任务
    function throttle (fn, delay) {
      let timer
      return function () {
        if (timer) return
        timer = setTimeout(() => {
          fn()
          timer = null
        }, delay)
      }
    }

1.2关键点还是改变this的指向

    function throttle (fn, delay) {
      let timer
      return function () {
        let context = this
        let args = arguments
        if (timer) return
        timer = setTimeout(() => {
          fn.apply(context, args)
          timer = null
        }, delay)
      }
    }

2.使用Date对象来实现

2.1综合前面的问题,直接写出来

  • 但是我们发现有一个问题,就是函数第一次会立即执行
    function throttle (fn, delay) {
      let pre = 0
      return function () {
        let now = new Date()
        let context = this
        let args = arguments
        if (now - pre > delay) {
          fn.apply(context, args)
          pre = now
        }
      }
    }

2.2可以第一次不立即执行吗?可以!

  • 我们判断,如果!pre就是第一次,第一次我们先拿到当前时间就可以了
    function throttle (fn, delay) {
      let pre = 0
      return function () {
        if (!pre) pre = new Date()
        let now = new Date()
        let context = this
        let args = arguments
        if (now - pre > delay) {
          fn.apply(context, args)
          pre = now
        }
      }
    }

3.我们讨论一下前两种方案的弊端

  • 假设我们有两次请求,第一次正常,第二次被节流了
  • 最后我们只执行了一次,这是我们不愿意看到的!
  • 如何解决?请看第4点

jieliu.png

4.Date结合定时器解决3.的弊端

  • 我们在2中代码的基础上来添加
  • 闭包的timer,如果在节流时间内,我们就定一个定时器来完成被吃掉的请求
  • 定时为剩下的时间remainTime=delay-(now-pre),定时前记得判断是否存在(存在就不用设置直接return就可以了),完成后记得要更新pretimer=null
    function throttle (fn, delay) {
      let pre = 0
      let timer
      return function () {
        if (!pre) pre = new Date()
        let now = new Date()
        let context = this
        let args = arguments
        let remainTime = delay - (now - pre)
        if (now - pre > delay) {
          fn.apply(context, args)
          pre = now
        } else {
          if (timer) return
          timer = setTimeout(() => {
            fn.apply(context, args)
            pre = now
            timer = null
          }, remainTime)
        }
      }
    }
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-18 17:32:12  更:2022-04-18 17:35:54 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 1:54:53-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码