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

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

js防抖


特点:


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



应用场景:


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

实现方式


第三方库实现

<inputtype="text"><!--html标签-->
<scriptsrc="" target="_blank">https://cdn.jsdelivr.net/npm/underscore@1.13.1/underscore-umd-min.js"></script>
<script>
constinputEl=document.querySelector("input")
letcounter=0
constinputChange=function(event) {
console.log(`发送了第${++counter}次网络请求`, this, event)
}
// 防抖处理
inputEl.οninput=_.debounce(inputChange, 2000)//当用户停止输入的时候延时2秒后执行
</script>

手动实现(原理)

基本实现:

functiondebounce(fn, delay) {
// 1.定义一个定时器, 保存上一次的定时器
lettimer=null
// 2.真正执行的函数
const_debounce=function() {
// 取消上一次的定时器
if (timer) clearTimeout(timer)
// 延迟执行
timer=setTimeout(() => {
// 外部传入的真正要执行的函数
fn()
}, delay)
}
return_debounce
}

this绑定/事件对象

functiondebounce(fn, delay) {
// 1.定义一个定时器, 保存上一次的定时器
lettimer=null
// 2.真正执行的函数
const_debounce=function(...args) {
// 取消上一次的定时器
if (timer) clearTimeout(timer)
// 延迟执行
timer=setTimeout(() => {
// 外部传入的真正要执行的函数
fn.apply(this, args)
}, delay)
}
return_debounce
}

第一次立即执行

functiondebounce(fn, delay, immediate=false) {
// 1.定义一个定时器, 保存上一次的定时器
lettimer=null
letisInvoke=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
}

取消功能

functiondebounce(fn, delay, immediate=false) {
// 1.定义一个定时器, 保存上一次的定时器
lettimer=null
letisInvoke=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>
<inputtype="text">
<scriptsrc="./05_debounce-v5-函数返回值.js"></script>
<script>
constinputEl=document.querySelector("input")
letcounter=0
constinputChange=function(event) {
console.log(`发送了第${++counter}次网络请求`, this, event)
// 返回值
return"aaaaaaaaaaaa"
}
// 防抖处理--拿到包装好的事件处理回调函数--回调函数的返回值是Promise
constdebounceChange=debounce(inputChange, 3000, false, (res) => {
console.log("拿到真正执行函数的返回值:", res)
})
consttempCallback= () => {
debounceChange().then(res=> {
console.log("Promise的返回值结果:", res)
})
}
inputEl.οninput=tempCallback
</script>
</body>
</html>

js节流


特点:


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




应用场景:


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

Ø监听页面的滚动事件;

Ø 鼠标移动事件;

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

实现方式:


第三方库实现

<inputtype="text"><!--html标签-->
<scriptsrc="" target="_blank">https://cdn.jsdelivr.net/npm/underscore@1.13.1/underscore-umd-min.js"></script>
<script>
constinputEl=document.querySelector("input")
letcounter=0
constinputChange=function(event) {
console.log(`发送了第${++counter}次网络请求`, this, event)
}
// 节流处理
inputEl.οninput=_.throttle(inputChange, 2000)//当用户不断触发事件按照2秒的频率执行
</script>

手动实现(原理)

基本实现:

functionthrottle(fn, interval, options) {
// 1.记录上一次的开始时间
letlastTime=0
// 2.事件触发时, 真正执行的函数
const_throttle=function() {
// 2.1.获取当前事件触发时的时间
constnowTime=newDate().getTime()
// 2.2.使用当前触发的时间和之前的时间间隔以及上一次开始的时间, 计算出还剩余多长事件需要去触发函数
constremainTime=interval- (nowTime-lastTime)
if (remainTime<=0) {
// 2.3.真正触发函数
fn()
// 2.4.保留上次触发的时间
lastTime=nowTime
}
}
return_throttle
}

控制开始执行一次(默认开启,后续可以通过参数来关闭)

function throttle(fn, interval, options = { leading: true, trailing: false }) {
// 1.记录上一次的开始时间
const { leading, trailing } = options
let lastTime = 0
// 2.事件触发时, 真正执行的函数
const _throttle = function() {
// 2.1.获取当前事件触发时的时间
const nowTime = new Date().getTime()
if (!lastTime && !leading) lastTime = nowTime
// 2.2.使用当前触发的时间和之前的时间间隔以及上一次开始的时间, 计算出还剩余多长事件需要去触发函数
const remainTime = interval - (nowTime - lastTime)
if (remainTime <= 0) {
// 2.3.真正触发函数
fn()
// 2.4.保留上次触发的时间
lastTime = nowTime
}
}
return _throttle
}

最后执行一次

function throttle(fn, interval, options = { leading: true, trailing: false }) {
// 1.记录上一次的开始时间
const { leading, trailing } = options
let lastTime = 0
let timer = null
// 2.事件触发时, 真正执行的函数
const _throttle = function() {
// 2.1.获取当前事件触发时的时间
const nowTime = new Date().getTime()
if (!lastTime && !leading) lastTime = nowTime
// 2.2.使用当前触发的时间和之前的时间间隔以及上一次开始的时间, 计算出还剩余多长事件需要去触发函数
const remainTime = interval - (nowTime - lastTime)
if (remainTime <= 0) {
if (timer) {
clearTimeout(timer)
timer = null
}
// 2.3.真正触发函数
fn()
// 2.4.保留上次触发的时间
lastTime = nowTime
return
}
if (trailing && !timer) {
timer = setTimeout(() => {
timer = null
lastTime = !leading ? 0: new Date().getTime()
fn()
}, remainTime)
}
}
return _throttle
}
相关文章
|
1天前
|
JavaScript 前端开发 安全
JavaScript函数详解
JavaScript函数的详细解析,包括函数的定义和调用方式(如一般格式、匿名函数、构造函数、自调用函数、箭头函数和严格模式)、函数参数(arguments对象、可变参数、默认参数值)、闭包的概念和应用实例。
JavaScript函数详解
|
3天前
|
JSON JavaScript 数据格式
手写JS实现深拷贝函数
本文介绍了如何实现一个深拷贝函数`deepClone`,该函数可以处理对象和数组的深拷贝,确保拷贝后的对象与原始对象在内存中互不干扰。通过递归处理对象的键值对和数组的元素,实现了深度复制,同时保留了函数类型的值和基础类型的值。
11 3
|
1天前
|
缓存 JavaScript 前端开发
了解js基础知识中的作用域和闭包以及闭包的一些应用场景,浅析函数柯里化
该文章详细讲解了JavaScript中的作用域、闭包概念及其应用场景,并简要分析了函数柯里化的使用。
了解js基础知识中的作用域和闭包以及闭包的一些应用场景,浅析函数柯里化
|
3天前
|
前端开发 数据可视化 开发者
D3.js 内置的动画函数
D3.js 内置的动画函数
|
3天前
|
JavaScript 前端开发
js防抖函数返回值问题解决方案
本文介绍了如何在JavaScript中创建一个带有返回值的防抖函数,通过结合Promise来实现。这种防抖函数可以在事件触发一定时间后再执行函数,并能处理异步操作的返回值。文章提供了防抖函数的实现代码和如何在实际项目中使用该防抖函数的示例。
14 1
|
4天前
|
移动开发 前端开发 JavaScript
原生JavaScript+canvas实现五子棋游戏_值得一看
本文介绍了如何使用原生JavaScript和HTML5的Canvas API实现五子棋游戏,包括棋盘的绘制、棋子的生成和落子、以及判断胜负的逻辑,提供了详细的代码和注释。
12 0
原生JavaScript+canvas实现五子棋游戏_值得一看
|
4天前
|
JavaScript 前端开发
JS 偏函数、函数柯里化~
该文章介绍了JavaScript中偏函数和函数柯里化的概念、实现方法和使用场景,通过代码示例展示了如何创建预设参数的函数以及如何将多参数函数转换成单参数函数的链式调用。
11 0
JS 偏函数、函数柯里化~
|
设计模式 前端开发 JavaScript
100行代码让您学会JavaScript原生的Proxy设计模式
100行代码让您学会JavaScript原生的Proxy设计模式
131 0
100行代码让您学会JavaScript原生的Proxy设计模式
|
2月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的客户关系管理系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的客户关系管理系统附带文章源码部署视频讲解等
73 2