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

应用场景:

Ø 游戏中的一些设计–王者荣耀 英雄的普攻;

Ø监听页面的滚动事件;

Ø 鼠标移动事件;

Ø 用户频繁点击按钮操作;

实现方式:

第三方库实现

<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月前
|
JavaScript 前端开发 Java
[JS]同事:这次就算了,下班回去赶紧补补内置函数,再犯肯定被主管骂
本文介绍了JavaScript中常用的函数和方法,包括通用函数、Global对象函数以及数组相关函数。详细列出了每个函数的参数、返回值及使用说明,并提供了示例代码。文章强调了函数的学习应结合源码和实践,适合JavaScript初学者和进阶开发者参考。
42 2
[JS]同事:这次就算了,下班回去赶紧补补内置函数,再犯肯定被主管骂
|
1月前
|
前端开发 JavaScript 开发者
除了 Generator 函数,还有哪些 JavaScript 异步编程解决方案?
【10月更文挑战第30天】开发者可以根据具体的项目情况选择合适的方式来处理异步操作,以实现高效、可读和易于维护的代码。
|
1月前
|
移动开发 前端开发 JavaScript
前端实训,刚入门,我用原生技术(H5、C3、JS、JQ)手写【网易游戏】页面特效
于辰在大学期间带领团队参考网易游戏官网的部分游戏页面,开发了一系列前端实训作品。项目包括首页、2021校园招聘页面和明日之后游戏页面,涉及多种特效实现,如动态图片切换和人物聚合效果。作品源码已上传至CSDN,视频效果可在CSDN预览。
33 0
前端实训,刚入门,我用原生技术(H5、C3、JS、JQ)手写【网易游戏】页面特效
|
2月前
|
JavaScript 前端开发
JavaScript 函数语法
JavaScript 函数是使用 `function` 关键词定义的代码块,可在调用时执行特定任务。函数可以无参或带参,参数用于传递值并在函数内部使用。函数调用可在事件触发时进行,如用户点击按钮。JavaScript 对大小写敏感,函数名和关键词必须严格匹配。示例中展示了如何通过不同参数调用函数以生成不同的输出。
|
2月前
|
存储 JavaScript 前端开发
JS函数提升 变量提升
【10月更文挑战第6天】函数提升和变量提升是 JavaScript 语言的重要特性,但它们也可能带来一些困惑和潜在的问题。通过深入理解和掌握它们的原理和表现,开发者可以更好地编写和维护 JavaScript 代码,避免因不了解这些机制而导致的错误和不一致。同时,不断提高对执行上下文等相关概念的认识,将有助于提升对 JavaScript 语言的整体理解和运用能力。
|
2月前
|
前端开发 JavaScript UED
JavaScript 中的函数防抖与节流详解及实用场景
在前端开发中,处理用户频繁触发的事件,如输入框的输入、按钮点击、窗口调整大小等,常常需要优化性能以减少无效操作。为此,函数防抖(debounce)和函数节流(throttle)是两种常见的性能优化手段。本文将详细介绍两者的区别与实现,并探讨它们的应用场景。
44 1
|
2月前
|
存储 JavaScript 前端开发
js中函数、方法、对象的区别
js中函数、方法、对象的区别
21 2
|
2月前
|
存储 JavaScript 前端开发
JavaScript数据类型全解:编写通用函数,精准判断各种数据类型
JavaScript数据类型全解:编写通用函数,精准判断各种数据类型
40 0
|
7月前
|
JavaScript
JS中防抖和节流的区别是什么
JS中防抖和节流的区别是什么
49 0
|
7月前
|
JavaScript 前端开发 UED
【面试题】面试官:说说你对js中的 防抖 和 节流 的理解
【面试题】面试官:说说你对js中的 防抖 和 节流 的理解