如何通过原生js实现一个节流函数和防抖函数?

如何通过原生js实现一个节流函数和防抖函数

一、js防抖

特点:

  1. 当事件触发时,相应的函数并不会立即触发,而是会等待一定的时间(非常短的时间);
  2. 当事件密集触发时,函数的触发会被频繁的推迟;
  3. 只有等待了一段时间也没有事件触发,才会真正的执行响应函数;

在这里插入图片描述

应用场景:

  • Ø输入框中频繁的输入内容,搜索或者提交信息;
  • Ø频繁的点击按钮,触发某个事件;
  • Ø监听浏览器滚动事件,完成某些特定操作;
  • Ø用户缩放浏览器的resize事件;

实现方式

第三方库实现

<input type="text"> <!--html标签-->

<script src="https://cdn.jsdelivr.net/npm/underscore@1.13.1/underscore-umd-min.js"></script>
<script>
const inputEl = document.querySelector("input")
let counter = 0
const inputChange = function(event) {
      console.log(`发送了第${++counter}次网络请求`, this, event)
}

// 防抖处理
inputEl.oninput = _.debounce(inputChange, 2000)//当用户停止输入的时候延时2秒后执行
</script>

手动实现(原理)

  • 基本实现:
function debounce(fn, delay) {
  // 1.定义一个定时器, 保存上一次的定时器
  let timer = null
  // 2.真正执行的函数
  const _debounce = function() {
    // 取消上一次的定时器
    if (timer) clearTimeout(timer)
    // 延迟执行
    timer = setTimeout(() => {
      // 外部传入的真正要执行的函数
      fn()
    }, delay)
  }

  return _debounce
}
  • this绑定/事件对象
function debounce(fn, delay) {
  // 1.定义一个定时器, 保存上一次的定时器
  let timer = null
  // 2.真正执行的函数
  const _debounce = function(...args) {
    // 取消上一次的定时器
    if (timer) clearTimeout(timer)
    // 延迟执行
    timer = setTimeout(() => {
      // 外部传入的真正要执行的函数
      fn.apply(this, args)
    }, delay)
  }
  return _debounce
}
  • 第一次立即执行
function debounce(fn, delay, immediate = false) {
  // 1.定义一个定时器, 保存上一次的定时器
  let timer = null
  let isInvoke = false

  // 2.真正执行的函数
  const _debounce = function(...args) {
    // 取消上一次的定时器
    if (timer) clearTimeout(timer)

    // 判断是否需要立即执行
    if (immediate && !isInvoke) {
      fn.apply(this, args)
      isInvoke = true
    } else {
      // 延迟执行
      timer = setTimeout(() => {
        // 外部传入的真正要执行的函数
        fn.apply(this, args)
        isInvoke = false
      }, delay)
    }
  }

  return _debounce
}

  • 取消功能
function debounce(fn, delay, immediate = false) { 
 // 1.定义一个定时器, 保存上一次的定时器  
 let timer = null  
 let isInvoke = false// 2.真正执行的函数  
const _debounce = function(...args) {
    // 取消上一次的定时器    
    if (timer) clearTimeout(timer)// 判断是否需要立即执行    if (immediate && !isInvoke) {      
    	fn.apply(this, args)      
    	isInvoke = true    
    } else {
      // 延迟执行      
      timer = setTimeout(() => {        
      	// 外部传入的真正要执行的函数        
      	fn.apply(this, args)        
      	isInvoke = false        
      	timer = null      
      }, delay)    
   	 }  
   }// 封装取消功能  
  	_debounce.cancel = function() {
      if (timer) clearTimeout(timer)
          timer = null
          isInvoke = false  
 	}return _debounce
}
  • 函数返回值
<body>
  
  <input type="text">
  <script src="./05_debounce-v5-函数返回值.js"></script>
  <script>
    const inputEl = document.querySelector("input")
    let counter = 0

    const inputChange = function(event) {
      console.log(`发送了第${++counter}次网络请求`, this, event)

      // 返回值
      return "aaaaaaaaaaaa"
    }

    // 防抖处理--拿到包装好的事件处理回调函数--回调函数的返回值是Promise
    const debounceChange = debounce(inputChange, 3000, false, (res) => {
      console.log("拿到真正执行函数的返回值:", res)
    })
    const tempCallback = () => {
      debounceChange().then(res => {
        console.log("Promise的返回值结果:", res)
      })
    }
    inputEl.oninput = tempCallback
  </script>
</body>
</html>

二、js节流

特点:

  1. 当事件触发时,会执行这个事件的响应函数;
  2. 如果这个事件会被频繁触发,那么节流函数会按照一定的频率来执行函数;
  3. 不管在这个中间有多少次触发这个事件,执行函数的频繁总是固定的;

在这里插入图片描述

应用场景:

  • Ø 游戏中的一些设计–王者荣耀 英雄的普攻;
  • Ø监听页面的滚动事件;
  • Ø 鼠标移动事件;
  • Ø 用户频繁点击按钮操作;

实现方式:

第三方库实现

<input type="text"> <!--html标签-->

<script src="https://cdn.jsdelivr.net/npm/underscore@1.13.1/underscore-umd-min.js"></script>
<script>
const inputEl = document.querySelector("input")
let counter = 0
const inputChange = function(event) {
      console.log(`发送了第${++counter}次网络请求`, this, event)
}

// 节流处理
inputEl.oninput =_.throttle(inputChange, 2000)//当用户不断触发事件按照2秒的频率执行
</script>

手动实现(原理)

  • 基本实现:
function throttle(fn, interval, options) {
  // 1.记录上一次的开始时间
  let lastTime = 0

  // 2.事件触发时, 真正执行的函数
  const _throttle = function() {

    // 2.1.获取当前事件触发时的时间
    const nowTime = new Date().getTime()

    // 2.2.使用当前触发的时间和之前的时间间隔以及上一次开始的时间, 计算出还剩余多长事件需要去触发函数
    const remainTime = interval - (nowTime - lastTime)
    if (remainTime <= 0) {
      // 2.3.真正触发函数
      fn()
      // 2.4.保留上次触发的时间
      lastTime = nowTime
    }
  }

  return _throttle
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值