面试必问题:JS防抖与节流
摘要:防抖与节流可谓是面试常见,其实很好理解,下面带你分分钟了解防抖与节流的基本思想与写法~
本文分享自华为云社区《JS防抖与节流快速了解与应用》,作者:北极光之夜。 。
一.速识防抖:
防抖与节流可谓是面试常见,其实很好理解,下面带你分分钟了解防抖与节流的基本思想与写法~
在这之前,比如我们先定义一个按钮,并绑定一个点击事件,执行要触发的事件:
<!-- 定义一个按钮 -->
<input type="button" id="btn" value="按钮" /> <script>
// 获取标签
var btn = document.getElementById("btn");
// 绑定事件
btn.addEventListener("click", real);
// 要触发的事件
function real(e) {
console.log("北极光之夜。");
console.log(e);
}
</script>
执行如下:

可以发现,一直点击会一直触发事件,如果这个事件为发送一个请求,那么这对与服务器来说是很不友好的。同样的请求因为用户的多次点击而多次发送请求,返回的结果和只点击一次是一样的,大大加重服务器压力和影响性能。所以,我们引入防抖的概念,简单来说,防抖就是通过setTimeout 的方式,在一定的时间间隔内,将多次触发变成一次触发。 直接看下面例子:
1.通过setTimeout的方式延迟执行:
第一种方式为通过设置setTimeout定时器的方式延迟执行,当快速多次点击的时候,每一次都会重置定时器,只有你一段时间都不点击时定时器才能到达条件并执行事件函数。
<input type="button" id="btn" value="按钮" />
<script>
var btn = document.getElementById("btn");
// 点击后触发trigger()函数,第一个参数为真实要执行的函数,第二个参数为定时器延迟时间
btn.addEventListener("click", trigger(real, 1000));
function trigger(fn, delay) {
// 设置time为定时器,初始为 null
var time = null;
// 闭包原理,返回一个函数
return function () {
// 如果定时器存在清空定时器
if (time) {
clearTimeout(time);
}
// 设置定时器,规定时间后执行真实要执行的函数
time = setTimeout(() => {
// 将参数传递给真实执行的函数,因为箭头函数继承父级作用域,所以直接...arguments
fn(...arguments);
}, delay);
};
}
//真实要执行函数
function real(e) {
console.log("北极光之夜。");
console.log(e);
} </script>
其中会利用闭包的原理形成作用域,使得定时器不会被下一次点击重复或清空。闭包不清楚的可以看我这篇文章: https://auroras.blog.csdn.net/article/details/119520871
运行结果如下,每次点击都延迟执行。狂点时只有停下后才会执行:

2.通过setTimeout的方式第一次会执行,后面不执行:
可以发现,第一种方式虽然延迟执行了,但是当用户第一次点的时候也要延迟执行,那就很不友好了。所以下面改进,使得第一次点的时候立即执行,狂点的时候只有第一次有效后面的都没效:
<input type="button" id="btn" value="按钮" />
<script>
var btn = document.getElementById("btn");
// 点击后触发trigger()函数,第一个参数为真实要执行的函数,第二个参数为定时器延迟时间
btn.addEventListener("click", trigger(real, 1000));
function trigger(fn, delay) {
// 设置time为定时器,初始为 null
var time = null;
return function () {
//定义一个firstClick,判断是否第一次执行,初始值为true
var firstClick = !time;
//第一次会立即执行
if (firstClick) {
fn(...arguments);
}
// 如果定时器存在清空定时器
if (time) {
clearTimeout(time);
}
// 设置定时器,此时firstClick会变为false,规定时间后time才会为null
time = setTimeout(() => {
time = null;
}, delay);
};
}
//真实要执行函数
function real(e) {
console.log("北极光之夜。");
console.log(e);
} </script>
运行结果如下,第一次点的时候立即执行,狂点的时候只有第一次有效后面的都没效:

3.通过setTimeout的方式第一次会执行和最后一次执行:
前两个其实就是防抖的经典例子了。这里是扩展知识,继续改进上面案例使得只点击一次的时候立即执行。当点击多次时第一次和最后一次执行。
<input type="button" id="btn" value="按钮" />
<script>
var btn = document.getElementById("btn");
// 点击后触发trigger()函数,第一个参数为真实要执行的函数,第二个参数为定时器延迟时间
btn.addEventListener("click", trigger(real, 1000));
function trigger(fn, delay) {
// 设置time为定时器,初始为 null
var time = null;
return function () {
//定义一个firstClick,判断是否第一次执行,初始值为true
var firstClick = !time;
//第一次会立即执行
if (firstClick) {
fn(...arguments);
}
// 如果定时器存在清空定时器
if (time) {
clearTimeout(time);
}
// 设置定时器,此时firstClick会变为false,规定时间后time才会为null
time = setTimeout(() => {
time = null;
// 如果firstClick为true,执行
if (!firstClick) {
fn(...arguments);
}
}, delay);
};
}
//真实要执行函数
function real(e) {
console.log("北极光之夜。");
console.log(e);
} </script>
运行结果如下,只点击一次的时候立即执行。当点击多次时第一次和最后一次执行。:

二.速识节流:
节流其实就很好理解了,减少一段时间的触发频率。简单来说,就是你一直狂点不停的话,它会每隔一定时间就执行一次。它与防抖最大的区别就是,无论事件触发多么频繁,都可以保证在规定时间内可以执行一次执行函数。下面利用计算时间戳实现:
<input type="button" id="btn" value="按钮" />
<script>
var btn = document.getElementById("btn");
// 点击后触发trigger()函数,第一个参数为真实要执行的函数,第二个参数为限制时间
btn.addEventListener("click", trigger(real, 500));
function trigger(fn, delay) {
// 设置bef,为上一次执行时间,初始为0
var bef = 0;
return function () {
// 获取当前时间戳
var now = new Date().getTime();
//如果当前时间减去上次时间大于限制时间时才执行
if (now - bef > delay) {
// 执行函数
fn(...arguments);
//执行后,上次时间赋值为这次执行时间
bef = now;
}
};
}
//真实要执行函数
function real(e) {
console.log("北极光之夜。");
console.log(e);
} </script>
运行结果如下,一点就运行。狂点不停的话,每隔500毫秒才执行一次。:

也可以用定时器实现节流,如下:
实现第一次点的时候也延迟执行,狂点不停的话,它会每隔一定时间就执行一次。
<input type="button" id="btn" value="按钮" />
<script>
var btn = document.getElementById("btn");
btn.addEventListener("click", trigger(real, 500));
function real(e) {
console.log("北极光之夜。");
console.log(e);
}
function trigger(fn, delay) {
// flag为ture
var flag = true;
return function () {
// 如果flag为true执行定时器
if (flag) {
setTimeout(() => {
//到规定时间后执行函数,同时 flag = true;
fn(...arguments);
flag = true;
}, delay);
}
// flag = false;防止一直执行
flag = false;
};
}
</script>
效果如下:

三.总结:
防抖与节流方法多多,不同的需求也会有不同的写法,重要的是搞清原理就好。防抖就是通过setTimeout 的方式,在一定的时间间隔内,将多次触发变成一次触发 。节流:就是减少一段时间的触发频率。防抖与节流最大的区别就是,无论事件触发多么频繁,都可以保证在规定时间内可以执行一次执行函数。
对了,给你们推荐一本好书,我今天刚看完的《秋园》,杨本芬老人的著作。看完久久不能平静。一本书映射着一个时代。同时也映射着那个时代的人们最纯粹,最朴实的酸甜苦辣。
面试必问题:JS防抖与节流的更多相关文章
- 深入理解JS防抖与节流
参考博客:JS防抖和节流,感谢作者的用心分享 日常开发过程中,滚动事件做复杂计算频繁调用回调函数很可能会造成页面的卡顿,这时候我们更希望把多次计算合并成一次,只操作一个精确点,JS把这种方式称为deb ...
- 因为它,我差点删库跑路:js防抖与节流
前言 前端踩雷:短时间内重复提交导致数据重复. 对于前端大佬来说,防抖和节流的技术应用都是基本操作.对于"兼职"前端开发的来说,这些都是需要躺平的坑. 我们今天就来盘一盘js防抖与 ...
- 2019 面试准备 - JS 防抖与节流 (超级 重要!!!!!)
Hello 小伙伴们,如果觉得本文还不错,记得给个 star , 你们的 star 是我学习的动力!GitHub 地址 本文涉及知识点: 防抖与节流 重绘与回流 浏览器解析 URL DNS 域名解析 ...
- js防抖和节流
今天在网上看到的,里面的内容非常多.说下我自己的理解. 所谓的防抖就是利用延时器来使你的最后一次操作执行.而节流是利用时间差的办法,每一段时间执行一次.下面是我的代码: 这段代码是右侧的小滑块跟随页面 ...
- js防抖和节流优化浏览器滚动条滚动到最下面时加载更多数据
防抖和节流,主要是用来防止过于平凡的执行某个操作,如浏览器窗口变化执行某个操作,监听某个input输入框keyup变化,瀑布流布局时Y轴滚动,图片加载. js函数的防抖 经过一段事件才执行某个操作,如 ...
- 详谈js防抖和节流
本文由小芭乐发表 0. 引入 首先举一个例子: 模拟在输入框输入后做ajax查询请求,没有加入防抖和节流的效果,这里附上完整可执行代码: <!DOCTYPE html> <html ...
- JS 防抖和节流
防抖和节流 在处理高频事件,类似于window的resize或者scorll,或者input输入校验等操作时.如果直接执行事件处理器,会增大浏览器的负担,严重的直接卡死,用户体验非常不好. 面对这种情 ...
- JS防抖和节流:原来如此简单
一.函数防抖 前端开发工作中,我们经常在一个事件发生后执行某个操作,比如鼠标移动时打印一些东西: window.addEventListener("mousemove", ()=& ...
- js防抖与节流了解一下
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
随机推荐
- 【LeetCode】94. 二叉树的中序遍历
94. 二叉树的中序遍历 知识点:二叉树:递归:Morris遍历 题目描述 给定一个二叉树的根节点 root ,返回它的 中序 遍历. 示例 输入:root = [1,null,2,3] 输出:[1, ...
- 搭建NFS服务
说明:这里是Linux服务综合搭建文章的一部分,本文可以作为单独搭建yum仓库的参考. 注意:这里所有的标题都是根据主要的文章(Linux基础服务搭建综合)的顺序来做的. 如果需要查看相关软件版本和主 ...
- 为什么每次下载后必须关闭掉IO流(十五)
读一个文件,忘记关闭了流,你在操作系统里对这个文件的写,删除等操作就会报错,告诉你这个文件被某个进程占用,这是为什么呢? java是从c++设计来的,但是无论是C语言还是C++,都需要手动释放内存,j ...
- centos7网卡配置文件
HWADDR=00:0c:29:a7:8e:ee TYPE=Ethernet BOOTPROTO=staticDEFROUTE=yes PEERROUTES=yesPEERROUTES=yes IPV ...
- OpenGL学习笔记(五)变换
目录 变换 向量 向量的运算 向量与标量运算 向量取反 向量加减 求向量长度 向量的单位化 向量相乘 点乘(Dot Product) 叉乘 矩阵 矩阵的加减 矩阵的数乘 矩阵相乘 矩阵与向量相乘 与单 ...
- 最全总结 JavaScript Array 方法详解
JavaScript Array 指南.png Array API 大全 (公众号: 前端自学社区).png 前言 我们在日常开发中,与接口打交道最多了,前端通过访问后端接口,然后将接口数据二次处理渲 ...
- Python 和 C/C++ 拓展程序如何性能优化?看这一篇文就够
作者:王璐璐 | 旷视 MegEngine 架构师 一. 背景 在 MegEngine imperative runtime 的早期开发中,我们面临着一些的性能优化问题.除了一些已知需要重构的地方(早 ...
- 面试官:你的App卡顿过吗?你是如何监控的?
一.故事开始 面试官:平时开发中有遇到卡顿问题吗?你一般是如何监控的? 来面试的小伙:额...没有遇到过卡顿问题,我平时写的代码质量比较高,不会出现卡顿. 面试官:... 这回答似乎没啥问题,但是如果 ...
- xubuntu下制作自定义的ISO文件
by han; 1.打开命令编辑器,建立文件 # sudo su # mkdir -p /opt/custom_conf/user_custom_conf/config 2.将自定义的设置复制保存到/ ...
- 1~n数字中1出现的个数
1~n数字中1出现的个数 LeetCode 给定一个整数 n,计算所有小于等于 n 的非负整数中数字 1 出现的个数. 感觉挺有意思 对于一个数,我们先局部分析一下,比如123456,我们考虑百位这个 ...