jinzh notes
jinzh notes

js中的防抖和节流

js中的防抖和节流
内容纲要

this指向

在了解防抖和节流之前,需要弄明白js中的this指向

  • 全局作用域或者普通函数中 this 指向全局对象 window
//直接打印
console.log(this) //window

//function声明函数
function bar () {console.log(this)}
bar() //window

//function声明函数赋给变量
var bar = function () {console.log(this)}
bar() //window

//自执行函数
(function () {console.log(this)})(); //window
  • 方法调用中谁调用 this 指向谁
//对象方法调用
var person = {
  run: function () {console.log(this)}
}
person.run() // person

//事件绑定
var btn = document.querySelector("button")
btn.onclick = function () {
  console.log(this) // btn
}
//事件监听
var btn = document.querySelector("button")
btn.addEventListener('click', function () {
  console.log(this) //btn
})

//jquery的ajax
$.ajax({
  self: this,
  type: "get",
  url: url,
  async: true,
  success: function (res) {
    console.log(this) // this指向传入$.ajxa()中的对象
    console.log(self) // window
  }
});
//这里说明以下,将代码简写为$.ajax(obj) ,this指向obj,在obj中this指向window,因为在在success方法中,独享obj调用自己,所以this指向obj
  • 在构造函数或者构造函数原型对象中 this 指向构造函数的实例
//不使用new指向window
function Person(name) {
  console.log(this) // window
  this.name = name;
}
Person('inwe')
//使用new
function Person(name) {
  this.name = name
  console.log(this) //people
  self = this
}
var people = new Person('iwen')
console.log(self === people) //true
//这里new改变了this指向,将this由window指向Person的实例对象people
  • 箭头函数中指向外层作用域的 this
var obj = {
  foo() {
    console.log(this);
  },
  bar: () => {
    console.log(this);
  }
}

obj.foo() // {foo: ƒ, bar: ƒ}
obj.bar() // window

防抖

防抖,顾名思义,防止抖动,以免把一次事件误认为多次,敲键盘就是一个每天都会接触到的防抖操作。

高频率触发的事件,在指定的单位时间内,只响应最后一次,如果在指定的时间再次触发,则重新计算时间(即后面触发的事件执行,替代了前面的事件)

防抖的应用场景:

  1. 登录、发短信等按钮避免用户点击太快,以致于发送了多次请求,需要防抖
  2. 调整浏览器窗口大小时,resize 次数过于频繁,造成计算过多,此时需要一次到位,就用到了防抖
  3. 文本编辑器实时保存,当无任何更改操作一秒后进行保存
  4. 搜索框输入文字后实时显示搜索结果

示例代码:

function debounce(fn) {
      let timeout = null; // 创建一个标记用来存放定时器的返回值
      return function () {
        clearTimeout(timeout);
         // 每当用户输入的时候把前一个 setTimeout clear 掉
        timeout = setTimeout(() => { 
        // 然后又创建一个新的 setTimeout, 这样就能保证输入字符后的 interval 间隔内
        // 如果还有字符输入的话,就不会执行 fn 函数
          fn.apply(this, arguments);
          //因为sayHi函数是在全局中运行,this默认指向了window
          //所以要用apply将inp的this传入
        }, 500);
      };
    }
    function sayHi() {
      console.log('防抖成功');
    }

    var inp = document.getElementById('inp');
    inp.addEventListener('input', debounce(sayHi)); // 防抖
//以下是本站搜索功能所使用的的防抖函数,和上面略有不同
function createDelayFunction(fn, timeout = 400) {
    let timeoutId = -1
    return (...args) => {
      clearTimeout(timeoutId)
      timeoutId = setTimeout(() => {
        fn(...args)
      }, timeout)
    }
  }

节流

节流,顾名思义,控制水的流量。控制事件发生的频率,如控制为1s发生一次,甚至1分钟发生一次。与服务端(server)及网关(gateway)控制的限流 (Rate Limit) 类似。

节流的应用场景:

  1. scroll 事件,每隔一秒计算一次位置信息等
  2. 浏览器播放事件,每个一秒计算一次进度信息等
  3. input 框实时搜索并发送请求展示下拉列表,每隔一秒发送一次请求 (也可做防抖)

示例代码:

function throttle(fn,delay){
    let valid = true
    return function() {
       if(!valid){
           //休息时间 暂不接客
           return false 
       }
       // 工作时间,执行函数并且在间隔期内把状态位设为无效
        valid = false
        setTimeout(() => {
            fn()
            valid = true;
        }, delay)
    }
}
/* 请注意,节流函数并不止上面这种实现方案,
   例如可以完全不借助setTimeout,可以把状态位换成时间戳,然后利用时间戳差值是否大于指定间隔时间来做判定。
   也可以直接将setTimeout的返回的标记当做判断条件-判断当前定时器是否存在,如果存在表示还在冷却,并且在执行fn之后消除定时器表示激活,原理都一样
    */

// 以下照旧
function showTop  () {
    var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
  console.log('滚动条位置:' + scrollTop);
}
window.onscroll = throttle(showTop,1000) 
//如果一直拖着滚动条进行滚动,那么会以1s的时间间隔,持续输出当前位置和顶部的距离

影翼

文章作者

发表回复

textsms
account_circle
email

jinzh notes

js中的防抖和节流
this指向 在了解防抖和节流之前,需要弄明白js中的this指向 全局作用域或者普通函数中 this 指向全局对象 window //直接打印 console.log(this) //window //function声明函数 function…
扫描二维码继续阅读
2021-09-15