3

应用
在我们开发过程中,会有一些用户操作,如滚动事件,输入事件等导致一直重复调用某函数,频率无限,使浏览器负担过重,导致页面卡顿。这时候就会用到防抖和节流来控制调用频率,减少浏览器负担。

区别:
防抖:设置一个时间段A来做延时,在事件触发后A时间段内没有再次触发事件,那么函数会在A时间段过后自动执行一次;如果在还没到达A时间段,再次触发事件,那么会根据最后一次触发来重新计算A时间段,延时执行;如下图:
防抖.jpeg

节流:设置一个时间段B,在事件触发后,B时间后再次执行,不管用户触发多少遍事件,函数只会每隔B段时间执行一次;
节流.jpeg

综上所述:防抖就是将无限次数变为最后一次执行,节流是将无限次数变为每隔一段时间执行;


实现:
防抖(debounce):防抖分为非立即执行与立即执行,非立即执行为触发后过一段时间才执行函数;立即执行为触发后马上执行函数,然后等待规定时间过后,再次触发有效,再次立即执行;

非立即执行:

<!DOCTYPE html>
<html lang="en">
 
<head>
 <meta charset="UTF-8">
 <title>加入防抖</title>
 <style type="text/css">
#box{width:500px;
height: 500px;
background: red;}
 </style>
</head>
 
<body>
 <div>
加入防抖后的输入:非立即执行
 <input type="text" name="debounce" id="debounce">
 <div id='box'>
在此移动
 </div>
 </div>
 <script type="text/javascript">
 // 防抖
 //非立即执行
 var i=0;
function debounce(fn, wait) { 
    console.log("执行")
    var timeout ; 
    return function(){
      if(timeout!== null) {
          clearTimeout(timeout)
        }
      timeout = setTimeout(fn,wait);    
    }
}
// 处理函数
function handle() {    
  i++;
   console.log(i+"次执行")
}
//触发事件 展示两种例子
//鼠标移动事件
 var box=document.getElementById('box');
 box.onmousemove=debounce(handle, 1000);
//键盘输入事件
var inp=document.getElementById('debounce');
inp.onkeyup=debounce(handle, 1000);
 </script>
</body>
 
</html>

立即执行:

<!DOCTYPE html>
<html lang="en">
 
<head>
 <meta charset="UTF-8">
 <title>加入防抖</title>
 <style type="text/css">
#box{width:500px;
height: 500px;
background: red;}
 </style>
</head>
 
<body>
 <div>
加入防抖后的输入:立即执行
 <input type="text" name="debounce" id="debounce">
 <div id='box'>
在此移动
 </div>
 </div>
 <script type="text/javascript">
 // 防抖
 //立即执行
 var i=0;
function debounce(fn, wait) { 
    var timeout ; 
    return function(){
      if(timeout!== null) {
          clearTimeout(timeout)
        }
      var flag=!timeout;
      timeout = setTimeout(function(){
        timeout=null;
      },wait);   
      if(flag){
        handle()
      } 
    }
}
// 处理函数
function handle() {    
  i++;
   console.log(i+"次执行")
}
//触发事件  展示两种例子
//鼠标移动事件
var box=document.getElementById('box');
 box.onmousemove=debounce(handle, 1000);
//键盘输入事件
var inp=document.getElementById('debounce');
inp.onkeyup=debounce(handle, 1000);
 </script>
</body>
 
</html>

节流(throttle):实现函数节流也有两种办法:时间戳和定时器;
时间戳方法:

<!DOCTYPE html>
<html lang="en">
 
<head>
 <meta charset="UTF-8">
 <title>加入防抖</title>
 <style type="text/css">
   #box{
     width:500px;
     height: 500px;
     background: red;
   }
 </style>
</head>
<body>
 <div>
    加入节流后的输入:时间戳
    <input type="text" name="debounce" id="inp">
    <div id='box'>
     在此移动
    </div>
 </div>
 <script type="text/javascript">
//节流
 var i=0;
var throttle = function(fn, way) {
    var prev = Date.now();
    return function() {
        var now = Date.now();
        if (now - prev >= way) {
            handle();
            prev = Date.now();
        }
    }
}
function handle() {
  i++;
    console.log(i+"次数");
}
//触发事件 展示两种例子
//鼠标移动事件
var box=document.getElementById('box');
 box.onmousemove=throttle(handle, 3000);
//键盘输入事件
var inp=document.getElementById('inp');
inp.onkeyup=throttle(handle, 3000);
</script>
</body>
 
</html>

定时器:

<!DOCTYPE html>
<html lang="en">
 
<head>
 <meta charset="UTF-8">
 <title>加入防抖</title>
 <style type="text/css">
#box{width:500px;
height: 500px;
background: red;}
 </style>
</head>
 
<body>
 <div>
加入节流后的输入:定时器
 <input type="text" name="debounce" id="inp">
 <div id='box'>
在此移动
 </div>
 </div>
 <script type="text/javascript">
 // 节流
 var i=0;
var throttle = function(fn, way) {
   var timer = null;
    return function() {
        if (!timer) {
            timer = setTimeout(function(){
              handle()
              timer=null;
            }, way);
        }
    }
}
function handle() {
  i++;
    console.log(i+"次数");
}
//触发事件 展示两种例子
//鼠标移动事件
var box=document.getElementById('box');
 box.onmousemove=throttle(handle, 2000);
//键盘输入事件
var inp=document.getElementById('inp');
inp.onkeyup=throttle(handle, 2000);
</script>
</body>
</html>

以上两种方式,都各有弊端,时间戳在最后一次触发后不执行函数,而定时器是第一次触发的时候没有立即执行函数,这两种方式无法完美的满足需求,所以我们优化了一下节流方式,如下:

<!DOCTYPE html>
<html lang="en">
 
<head>
 <meta charset="UTF-8">
 <title>加入防抖</title>
 <style type="text/css">
#box{width:500px;
height: 500px;
background: red;}
 </style>
</head>
 
<body>
 <div>
加入节流后的输入:定时器
 <input type="text" name="debounce" id="inp">
 <div id='box'>
在此移动
 </div>
 </div>
 <script type="text/javascript">
 // 节流
var i=0;
var throttle = function(fn, way) {
  console.log(11)
    var timer = null;
    var startTime = Date.now();
    return function() {
      var nowTime = Date.now();
      var remaining = way - (nowTime - startTime);  //剩余时间
      clearTimeout(timer);
      if (remaining <= 0) {      // 第一次触发立即执行
           handle();
          startTime = Date.now();
      } else {
        timer = setTimeout(function(){
           i++;
        console.log(i+"次数"); 
        startTime = Date.now();
        }, remaining);   //取消当前计数器并计算新的remaining
      }
    }
}
function handle() {
  i++;
    console.log(i+"次数");
}
//触发事件 展示两种例子
//鼠标移动事件
var box=document.getElementById('box');
 box.onmousemove=throttle(handle, 3000);
//键盘输入事件
var inp=document.getElementById('inp');
inp.onkeyup=throttle(handle, 3000);
 </script>
</body>
 
</html>

时间戳+定时器版如有优化建议,欢迎提出!跪谢!


BerylLee
21 声望1 粉丝