目录
- 前言
- 正文内容
- 防抖
- 非立即执行方式
- 立即执行方式
- 节流
- 时间戳节流
- 定时器节流
- 防抖和节流的区别
- 总结
前言
在前段日子,在内心的逼迫下跟着众多大佬的脚步,磨磨蹭蹭慢慢悠悠的学完了一些原生JavaScript底层的知识。产生了很多感触,编程技术太多了,写得出东西不代表真的掌握了,而理解一项技术的底层原理更加重要,只有了解了整个运行的过程,才能分析调优或者创新新的框架。
本来打算先学习点别的,但是思索之后,还是决定顺带着继续一点点磨 JavaScript,毕竟这东西真的很重要。
正文内容
原来在写作业时,比较注重的只有程序功能是否实现,对于效率确实很少考虑,但是愈发深入的学习
让我了解到每一项成熟的技术最后都要走向商用或者应用场景变得非常大型,那么每一次运行程序的成本就要尽量压低,一次响应节省1s,那么10000次相应就会节约出快三个小时,所以对于效率的考虑我们应该作为一种编程习惯与思想,融入写代码的过程中。
防抖
那么什么是防抖呢(通俗的说就是你越急我越不让你执行,乖乖等着是最快的办法),上学期在嵌入式设计这门课中有学过这个概念。通俗的说就是因为你的按钮没有设置相关检测程序,以至于在人为按动之后,无意间的震动,系统也会进行响应,从而执行很多遍按钮事件。
那JavaScript里的防抖自然也是这个意思,比如 ajax函数,如果不能很好地设置极短时间内次数拦截,那么将会给后台造成很大压力,比如。
这里在网页里写了个div进行测试
<div id="content"
style="height:150px;background-color:#ccc;font-size:80px;"></div>
这是模拟与后台通信的方法
javascript"> let content = document.getElementById('content');
function count() {
console.log("向后台发送请求!")
}
content.onmousemove = count; //绑定鼠标移动事件
可以清楚的看到,如果我们没有采取任何措施,那么将存在短时间访问急剧增加的风险,如果每一次请求的代码执行量都很大,要经过复杂的算法和计算,那这样就很可能导致服务器宕机。于是们更改一下代码。
通过查资料我们知道了防抖函数有两种,非立即执行和立即执行。
非立即执行方式
这种方式的意思是触发事件后函数不会立即执行,只会在最后一次触发事件后等待设定的wait时间结束时执行一次
<div id="content"
style="height:150px;background-color:#ccc;font-size:80px;"></div>
javascript"> let content = document.getElementById('content');
function count() {
console.log("向后台发送请求!!!!!")
}
// 非立即执行版
function debounce(func, wait) {
let timer;
return function () {
console.log("触发页面事件")
if (timer) clearTimeout(timer);
timer = setTimeout(func, wait)
}
}
content.onmousemove = debounce(count, 1000);
可以清楚地看到事件触发了很多次,但是经过等待只执行了一次func
,事件触发时先等待完成再进行函数func
的执行。
立即执行方式
接下来我们看看立即执行的版本
这种方式的意思是触发事件后函数会立即执行,然后 n 秒内不触发事件才能继续执行函数的效果
<div id="content"
style="height:150px;background-color:#ccc;font-size:80px;"></div>
javascript"> let content = document.getElementById('content');
function count() {
console.log("向后台发送请求!!!!!")
}
// 立即执行版
function debounce(func, wait) {
let timer;
return function () {
if (timer) clearTimeout(timer);
let callNow = !timer;
timer = setTimeout(() => {
timer = null;
}, wait)
if (callNow) func();
}
}
content.onmousemove = debounce(count, 1000);
可以看到立即执行的方式是先执行再等待,这里引用了一个中间变量 callNow
,来判断执行完一次func
之后是否已经完成等待,一旦完成,就会把时间对象timer
变为null
,也就预示着下一次事件触发时callNow
的值会变成true
,就可以执行函数fun
节流
先把定义拉上来:指连续触发事件但是在 n 秒中只执行一次函数。
同样有两个版本,时间戳和定时器版。
时间戳节流
这种方式是利用每个时刻与上个时刻的时间差来判断是否达到等待时长。
javascript"> let content = document.getElementById('content');
function count() {
console.log("向后台发送请求!!!!!")
}
// 时间戳版
function throttle(func, wait) {
let previous = 0;
return function () {
let now = Date.now();//返回自1970年1月1日 00:00:00到当前时间的毫秒数。
if (now - previous > wait) {
func();
previous = now;
}
}
}
content.onmousemove = throttle(count, 1000);
我们可以清晰地看到节流是固定每1s执行一次,在这段代码中,我们通过取时间差来判断等待时间是否达到了 1000ms,进而判断是否可以执行函数 func
。
定时器节流
这种方式利用setTimeout
实现两个操作同时进行(标识符timeout
赋值和执行函数func
),从而达到节流的目的。
javascript"> let content = document.getElementById('content');
function count() {
console.log("向后台发送请求!!!!!")
}
// 定时器版
function throttle(func, wait) {
let timeout;
return function () {
console.log(timeout)
if (!timeout) {
timeout = setTimeout(() => {
timeout = null;
func()
}, wait)
}
console.log("-------")
}
}
content.onmousemove = throttle(count, 1000);
timeout
作为标志符,再等待时间结束前,他是一直具有值的,所以不会执行判断语句内部的语句。
防抖和节流的区别
防抖动是将多次执行变为最后一次执行,节流是将多次执行变成每隔一段时间执行。
总结
防抖动:触发高频事件后 n 秒内函数只会执行一次,如果 n 秒内高频事件再次被触发,则重新计算时间
举例:登录、发短信等按钮避免用户点击太快,以致于发送了多次请求,需要防抖
非立即执行方式: 高频触发事件-----等待指定时间-----执行一次-----下一次触发事件-----(循环往复)
立即执行方式: 高频触发事件-----执行一次-----等待指定时间-----下一次触发事件-----(循环往复)
节流:高频事件触发,但在 n 秒内只会执行一次,所以节流会稀释函数的执行频率
举例:浏览器播放事件,每个一秒计算一次进度信息
高频触发事件-----(固定的等待时长)-----执行一次-----继续保持触发事件-----(固定的等待时长)-----(循环往复)