防抖 (debounce)
所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
ps: 重置普攻,百度翻译要输完停止一定时间后才翻译。
没有防抖和节流的缺点:
- 函数触发频率过高导致的响应速度跟不上触发频率,出现延迟,假死或卡顿的现象。
- 浪费请求资源
策略 :
当事件被触发时,设定一个周期延时执行动作,若周期又被触发,则重新设定周期,直到周期结束,执行动作。
在后期有拓展了前缘防抖函数,即执行动作在前,设定延迟周期在后,周期内有事件被触发,不执行动作,且周期重新设定。
案例 :停止输入后将输入的字符串翻转
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>防抖 </title>
<style>
* {
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
}
body {
display: flex;
justify-content: center;
align-items: center;
}
.container {
display: flex;
justify-content: space-around;
width: 800px;
height: 400px;
padding: 20px;
box-shadow: 0 0 8px #222;
}
.container div {
width: 350px;
height: 380px;
padding: 8px;
border: 1px solid #ccc;
font-size: 18px;
line-height: 20px;
word-break: break-all;
}
.input-box {
color: #368;
outline: none;
}
.show-box {
color: orange;
}
</style>
</head>
<body>
<div class="container">
<div class="input-box" contenteditable></div>
<div class="show-box"></div>
</div>
<script>
var oInput = document.querySelector('.input-box')
var oShow = document.querySelector('.show-box')
var timeOut;//这个timeOut必须是全局变量
oInput.addEventListener('input', function () {
timeOut && clearTimeout(timeOut);
timeOut = setTimeout(function () {
oShow.innerText = translate(oInput.innerText);
}, 500);
}, false);
function translate(str) {
return str.split("").reverse().join("");
}
</script>
</body>
</html>
节流 (throttling)
所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数。**节流会稀释函数的执行频率。
对于节流,有多种方式可以实现 时间戳 定时器 束流等。
ps : 技能CD
应用场景:
-
鼠标连续不断地触发某事件(如点击),只在单位时间内只触发一次;
-
在页面的无限加载场景下,需要用户在滚动页面时,每隔一段时间发一次 ajax 请求,而不是在用户停下滚动页面操作时才去请求数据;
-
监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断;
策略:
固定周期内,只执行一次动作,若没有新事件触发,不执行。周期结束后,又有事件触发,开始新的周期。
特点 :
连续高频触发事件时,动作会被定期执行,响应平滑
计时器版
javascript
var oCon = $('.container');
var num = 0;
var valid = true;
oCon.addEventListener('mousemove', function () {
if (!valid) {
return false;
}
valid = false;
setTimeout(function () {
count();
valid = true;
}, 500);
}, false);
function count() {
oCon.innerText = num++;
}
时间戳版
javascript
var oCon = $('.container');
var num = 0;
var time = Date.now();
oCon.addEventListener('mousemove', function () {
if (Date.now() - time < 600) {
return false;
}
time = Date.now();
count();
}, false);
function count() {
oCon.innerText = num++;
}
束流器版
一般用在游戏中,元素以不同频率运动
这样做的好处是可以把所有元素用同一个定时器来管理,用速差来做不同频率的运动
javascript
var oCon = $('.container');
var num = 0;
var time = 0;
oCon.addEventListener('mousemove', function () {
time++;
if (time % 30 !== 0) {
return false;
}
console.log(time)
count();
}, false);
function count() {
oCon.innerText = num++;
}
案例:同一个定时器中 红色小球运动两次 蓝色小球运动一次
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>定时器运动 </title>
<style>
* {
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
}
div {
position: absolute;
width: 100px;
height: 100px;
border-radius: 50%;
}
.red {
top: 100px;
background-color: red;
}
.blue {
background-color: blue;
}
</style>
</head>
<body>
<div class="red"></div>
<div class="blue"></div>
<script src="js/common.js"></script>
<script>
var oRed = $('.red');
var oBlue = $('.blue');
var speed = 0;
var counter = 0;
var time;
time = setInterval(function () {
speed += .1;
counter++;
oRed.style.left = oRed.offsetLeft + speed
+ 'px';
if (counter % 2 === 0) {
oBlue.style.left = oBlue.offsetLeft + speed
+ 'px';
}
}, 1000 / 30);
</script>
</body>
</html>