[JavaScript] 函数节流(throttle)和函数防抖(debounce)
js 的函数节流(throttle)和函数防抖(debounce)概述
函数防抖(debounce)
一个事件频繁触发,但是我们不想让他触发的这么频繁,于是我们就设置一个定时器让这个事件在 xxx 秒之后再执行。如果 xxx 秒内触发了,则清理定时器,重置等待事件 xxx 秒
比如在拖动 window 窗口进行 background 变色的操作的时候,如果不加限制的话,随便拖个来回会引起无限制的页面回流与重绘
或者在用户进行 input 输入的时候,对内容的验证放在用户停止输入的 300ms 后执行(当然这样不一定好,比如银行卡长度验证不能再输入过程中及时反馈)
一段代码实现窗口拖动变色
<script>
let body = document.getElementsByTagName("body")[0];
let index = 0;
if (body) {
window.onresize = function() {
index++;
console.log("变色" + index + "次");
let num = [Math.ceil(Math.random() * 255), Math.ceil(Math.random() * 255), Math.ceil(Math.random() * 255)];
body.style.background = "rgb(" + num[0] + "," + num[1] + "," + num[2] + ")"; //晃瞎眼睛
};
}
</script>
简单的防抖
使用 setTimeout 进行延迟处理,每次触发事件时都清除掉之前的方法
<script>
let body = document.getElementsByTagName("body")[0];
let index = 0;
let timer = null;
if (body) {
window.onresize = function() {
//如果在一秒的延迟过程中再次触发,就将定时器清除,清除完再重新设置一个新的
clearTimeout(timer);
timer = setTimeout(function() {
index++;
console.log("变色" + index + "次");
let num = [Math.ceil(Math.random() * 255), Math.ceil(Math.random() * 255), Math.ceil(Math.random() * 255)];
body.style.background = "rgb(" + num[0] + "," + num[1] + "," + num[2] + ")";
}, 1000); //反正就是等你什么都不干一秒后才会执行代码
};
}
</script>
抽离 debounce
但是目前有一个问题,就是代码耦合,这样不够优雅,将防抖和变色分离一下
<script>
let body = document.getElementsByTagName("body")[0];
let index = 0;
let lazyLayout = debounce(changeBgColor, 1000);
window.onresize = lazyLayout;
function changeBgColor() {
index++;
console.log("变色" + index + "次");
let num = [Math.ceil(Math.random() * 255), Math.ceil(Math.random() * 255), Math.ceil(Math.random() * 255)];
body.style.background = "rgb(" + num[0] + "," + num[1] + "," + num[2] + ")";
}
//函数去抖(连续事件触发结束后只触发一次)
function debounce(func, wait) {
let timeout, context, args; //默认都是undefined
return function() {
context = this;
args = arguments;
if (timeout) clearTimeout(timeout);
timeout = setTimeout(function() {
//执行的时候到了
func.apply(context, args);
}, wait);
};
}
</script>
underscore.js 的 debounce
underscore.js 实现的 debounce 已经经过检验
//1.9.1
_.debounce = function(func, wait, immediate) {
var timeout, result;
var later = function(context, args) {
timeout = null;
if (args) result = func.apply(context, args);
};
var debounced = restArguments(function(args) {
if (timeout) clearTimeout(timeout);
if (immediate) {
var callNow = !timeout;
timeout = setTimeout(later, wait);
if (callNow) result = func.apply(this, args);
} else {
timeout = _.delay(later, wait, this, args);
}
return result;
});
debounced.cancel = function() {
clearTimeout(timeout);
timeout = null;
};
return debounced;
};
函数节流(throttle)
简单的节流
一个事件频繁触发,但是在 xxx 秒内只能执行一次代码
//上面的变色在节流中就是这样写了
<script>
let doSomething = true;
let body = document.getElementsByTagName("body")[0];
let index = 0;
window.onresize = function() {
if (!doSomething) return;
doSomething = false;
setTimeout(function() {
index++;
console.log("变色" + index + "次");
let num = [Math.ceil(Math.random() * 255), Math.ceil(Math.random() * 255), Math.ceil(Math.random() * 255)];
body.style.background = "rgb(" + num[0] + "," + num[1] + "," + num[2] + ")";
doSomething = true;
}, 1000);
};
</script>
分离出 throttle 函数
跟上面的防抖差不多,分离一下,降低代码的耦合度
<script>
let body = document.getElementsByTagName("body")[0];
let index = 0;
let lazyLayout = throttle(changeBgColor, 1000);
window.onresize = lazyLayout;
function changeBgColor() {
index++;
console.log("变色" + index + "次");
let num = [Math.ceil(Math.random() * 255), Math.ceil(Math.random() * 255), Math.ceil(Math.random() * 255)];
body.style.background = "rgb(" + num[0] + "," + num[1] + "," + num[2] + ")";
}
//函数去抖(连续事件触发结束后只触发一次)
function throttle(func, wait) {
let context,
args,
doSomething = true;
return function() {
context = this;
args = arguments;
if (!doSomething) return;
doSomething = false;
setTimeout(function() {
//执行的时候到了
func.apply(context, args);
doSomething = true;
}, wait);
};
}
</script>
underscore.js 中 throttle 函数实现
_.throttle = function(func, wait, options) {
var timeout, context, args, result;
var previous = 0;
if (!options) options = {};
var later = function() {
previous = options.leading === false ? 0 : _.now();
timeout = null;
result = func.apply(context, args);
if (!timeout) context = args = null;
};
var throttled = function() {
var now = _.now();
if (!previous && options.leading === false) previous = now;
var remaining = wait - (now - previous);
context = this;
args = arguments;
if (remaining <= 0 || remaining > wait) {
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
previous = now;
result = func.apply(context, args);
if (!timeout) context = args = null;
} else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining);
}
return result;
};
throttled.cancel = function() {
clearTimeout(timeout);
previous = 0;
timeout = context = args = null;
};
return throttled;
};
防抖和节流是用来干什么的?
防抖的用处
- 绑定 scroll 滚动事件,resize 监听事件
- 鼠标点击,执行一个异步事件,相当于让用户连续点击事件只生效一次(很有用吧)
- 还有就是输入框校验事件(但是不一定好使,比如校验银行卡长度,当你输入完之后已经超出 100 个字符,正常应该是超出就提示错误信息)
节流的用处
- 当然还是鼠标点击啦,但是这个是限制用户点击频率。类似于你拿把 ak47 射击,枪的射速是 100 发/分钟,但是的手速达到 1000 按/分钟,就要限制一下喽(防止恶意刷子)
- 根据屏幕滚动到底部加载更多的功能
其实二者主要就是为了解决短时间内连续多次重复触发和大量的 DOM 操作的问题,来进行性能优化(重点是同时还能接着办事,并不耽误)
防抖主要是一定在 xxx 秒后执行,而节流主要是在 xxx 内执行(时间之后,时间之内)
右边那个快速目录就是加了个 throttle,控制台的执行速度就减少了(快速目录是看了掘金的目录之后弄的,确实方便了好多,对于长文本的阅读体验好了不少)
文章写的时候用的 underscore 1.8.2 版本,实现也是参考 underscore 的源码,实现方式与 underscore 最新有些代码还是不太一样了。(功能还是相同的)
[JavaScript] 函数节流(throttle)和函数防抖(debounce)的更多相关文章
- javascript 函数节流 throttle 解决函数被频繁调用、浏览器卡顿的问题
* 使用setTimeout index.html <html> <head> <meta charset="UTF-8"> <title ...
- 函数节流throttle和防抖debounce
throttle 函数节流 不论触发函数多少次,函数只在设定条件到达时调用第一次函数设定,函数节流 1234567891011 let throttle = function(fn,intervalT ...
- js 函数节流throttle 函数去抖debounce
1.函数节流throttle 通俗解释: 假设你正在乘电梯上楼,当电梯门关闭之前发现有人也要乘电梯,礼貌起见,你会按下开门开关,然后等他进电梯: 但是,你是个没耐心的人,你最多只会等待电梯停留一分钟: ...
- JS中的函数节流throttle详解和优化
JS中的函数节流throttle详解和优化在前端开发中,有时会为页面绑定resize事件,或者为一个页面元素绑定拖拽事件(mousemove),这种事件有一个特点,在一个正常的操作中,有可能在一个短的 ...
- js 高程 函数节流 throttle() 分析与优化
在 js 高程 22.3.3章节 里看到了 函数节流 的概念,觉得给出的代码可以优化,并且概念理解可以清晰些,所以总结如下: 先看 函数节流 的定义,书上原话(斜体表示): 产生原因/适用场景: 浏览 ...
- 微信小程序:防止多次点击跳转(函数节流)
场景 在使用小程序的时候会出现这样一种情况:当网络条件差或卡顿的情况下,使用者会认为点击无效而进行多次点击,最后出现多次跳转页面的情况,就像下图(快速点击了两次): 解决办法 然后从 轻松理解JS函数 ...
- 详解防抖函数(debounce)和节流函数(throttle)
本文转自:https://www.jianshu.com/p/f9f6b637fd6c 闭包的典型应用就是函数防抖和节流,本文详细介绍函数防抖和节流的应用场景和实现. 函数防抖(debounce) 函 ...
- js 函数的防抖(debounce)与节流(throttle)
原文:函数防抖和节流: 序言: 我们在平时开发的时候,会有很多场景会频繁触发事件,比如说搜索框实时发请求,onmousemove, resize, onscroll等等,有些时候,我们并不能或者不想频 ...
- 深入理解javascript函数进阶系列第三篇——函数节流和函数防抖
前面的话 javascript中的函数大多数情况下都是由用户主动调用触发的,除非是函数本身的实现不合理,否则一般不会遇到跟性能相关的问题.但在一些少数情况下,函数的触发不是由用户直接控制的.在这些场景 ...
随机推荐
- Linux 下配置Nginx,MySql,php-fpm开机启动
一. Nginx 开机启动 1.在/etc/init.d/目录下创建脚本 vim /etc/init.d/nginx 2.编写脚本内容 (将以下复制进去相应改动安装路径) #!/bin/bash # ...
- java 四舍五入保留两位小数
// 保留两位小数 System.out.println(Double.parseDouble(String.format("%.2f", 55.5454545454))); // ...
- 面试题之小炼牛刀zip,lambda,map
# 现有两元祖,(('a'),('b')),(('c'),('d'))# 请使用python中匿名函数生成列表[{'a':'c'},{'b':'d'}]t1=(('a'),('b'))t2=(('c' ...
- Python实现微信消息防撤回
微信(WeChat)是腾讯公司于2011年1月21日推出的一款社交软件,8年时间微信做到日活10亿,日消息量450亿.在此期间微信也推出了不少的功能如:“摇一摇”.“漂流瓶”.“朋友圈”.“附近的人” ...
- Python-定时爬取指定城市天气(一)-发送给关心的微信好友
一.背景 上班的日子总是3点一线,家里,公司和上班的路径,对于一个特别懒得我来说,经常遇到上班路上下雨了,而我却没带伞,多么痛的领悟.最近对python有一种狂热的学习热情,写了4年多的C++代码,对 ...
- Morris遍历-如何用空间复杂度O(1)来遍历二叉树
参照和学习: https://www.cnblogs.com/AnnieKim/archive/2013/06/15/morristraversal.html 解决的问题:如何使用空间复杂度O(1), ...
- 运维DBA要不要学python
运维DBA要不要学python 我个人认为是:要 现在python在运维数据库的工作中主要用在 1.编写一些运维脚本 2.编写运维管理平台 3.研究互联网大厂的运维脚本/工具并应有 特别是运维开源数据 ...
- SQLServer之创建数据库架构
创建数据库架构注意事项 包含 CREATE SCHEMA AUTHORIZATION 但未指定名称的语句仅允许用于向后兼容性. 该语句未引起错误,但未创建一个架构. CREATE SCHEMA 可以在 ...
- iOS 好文源码收藏
bireme 大佬的 iOS 保持界面流畅的技巧 https://blog.ibireme.com/2015/11/12/smooth_user_interfaces_for_ios/ 深入理解Run ...
- windows本地安全策略实验-远程桌面连接锁定账户
windows本地安全策略实验-远程桌面连接锁定账户 实验环境: 服务端:Win7-1:10.10.10.136,开启远程桌面服务 客户端:win7-2:10.10.10.153 确保客户端和服务端能 ...