节流(throttle)

节流的应用场景

  1. DOM元素的拖拽功能实现
  2. 射击游戏
  3. 计算鼠标移动的距离
  4. 监听scroll滚动

节流的原理

原理:n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效

代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<style>
    #container{
    
    
        width: 100%;
        height:200px;
        line-height: 200px;
        text-align: center;
        color:#fff;
        background-color: #444;
        font-size: 30px;
    }
</style>
<body>
    <div id="container"></div>
    //引入underscore包
    <script src="http://cdn.bootcss.com/underscore.js/1.9.1/underscore.js"></script>
    <script>
        let count = 0;
        //演示时间是如何频繁发生的
        let container = document.querySelector("#container");
        function doSomeThing() {
    
    
        //可能会做回调或者ajax请求
        container.innerHTML = count++;
        }
        let doSome = _.throttle(doSomeThing,2000,{
    
    
            leading:true,//设置第一次是否触发,true表示不禁止,false表示禁止
            trailing:false,//设置最后一次是否触发,true表示不禁止,false表示禁止
        });
        //给container绑定鼠标移动事件
        container.onmousemove = doSome;
    </script>
</body>
</html>

节流的分类

节流分为时间戳定时器两种。

  • 时间戳版的函数触发是在时间段内开始的时候。leading:true,trailing:false
  • 定时器版的函数触发是在时间段内结束的时候。leading:false,trailing:true

手写节流函数

时间戳版:

index.html文件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<style>
    #container{
    
    
        width: 100%;
        height:200px;
        line-height: 200px;
        text-align: center;
        color:#fff;
        background-color: #444;
        font-size: 30px;
    }
</style>
<body>
    <div id="container"></div>
    <!-- //引入throttle.js文件 -->
    <script src="./throttle.js"></script>
</body>
</html>

throttle.js文件:

//第一次触发,最后一次不触发
function throttle(func,wait){
    
    
    let context,args;
    //之前的时间戳
    let old = 0;
    return function(){
    
    
        //改变this指向,使this指向container
        context = this;
        //参数
        args = arguments;
        //获取当前的时间戳
        let now = new Date().valueOf()
        if(now-old > wait){
    
    
            //立即执行
            func.apply(context,args)
            old = now;
        }
    }
}

let count = 0;
//演示时间是如何频繁发生的
let container = document.querySelector("#container");
function doSomeThing() {
    
    
  //可能会做回调或者ajax请求
  container.innerHTML = count++;
}
let doSome = throttle(doSomeThing,2000);
//给container绑定鼠标移动事件
container.onmousemove = doSome;

定时器版:

index.html文件同上
throttle.js文件:

//第一次不触发,最后一次触发
function throttle(func,wait){
    
    
    let context,args,timeout;
    return function(){
    
    
        //改变this指向,使this指向container
        context = this;
        //参数
        args = arguments;
        //第一次timeout为undefined,!timeout为true,if内代码
        if(!timeout){
    
    
            timeout = setTimeout(()=>{
    
    
                //在wait时间内!timeout为false,再怎么触发函数都不会执行
                timeout = null;
                func.apply(context,args)
            },wait)
        }
    }
}

let count = 0;
//演示时间是如何频繁发生的
let container = document.querySelector("#container");
function doSomeThing() {
    
    
  //可能会做回调或者ajax请求
  container.innerHTML = count++;
}
let doSome = throttle(doSomeThing,2000);
//给container绑定鼠标移动事件
container.onmousemove = doSome;

时间戳和定时器双剑合璧版:
leading:true,trailing:true
index.html文件同上
throttle.js文件:

function throttle(func,wait){
    
    
    let context,args,timeout;
    let old = 0;
    let later = function(){
    
    
        old = new Date().valueOf();
        timeout = null;
        func.apply(context,args)
    }
    return function(){
    
    
        //改变this指向,使this指向container
        context = this;
        //参数
        args = arguments;
        let now = new Date().valueOf();
        if(now-old > wait){
    
    
            if(timeout){
    
    
                clearTimeout(timeout);
                timeout = null;
            }
            func.apply(context,args)
            old = now;
        }else if(!timeout){
    
    
            timeout = setTimeout(later,wait)
        }
    }
}

let count = 0;
//演示时间是如何频繁发生的
let container = document.querySelector("#container");
function doSomeThing() {
    
    
  //可能会做回调或者ajax请求
  container.innerHTML = count++;
}
let doSome = throttle(doSomeThing,2000);
//给container绑定鼠标移动事件
container.onmousemove = doSome;

完整优化版:
index.html文件同上
throttle.js文件:

function throttle(func,wait,options){
    
    
    let context,args,timeout;
    let old = 0;
    if(!options) options = {
    
    }
    let later = function(){
    
    
        old = new Date().valueOf();
        timeout = null;
        func.apply(context,args)
    }
    return function(){
    
    
        //改变this指向,使this指向container
        context = this;
        //参数
        args = arguments;
        let now = new Date().valueOf();
        if(options.leading === false && !old){
    
    
            old = now;
        }
        if(now-old > wait){
    
    
            if(timeout){
    
    
                clearTimeout(timeout);
                timeout = null;
            }
            func.apply(context,args)
            old = now;
        }else if(!timeout && options.trailing != false){
    
    
            timeout = setTimeout(later,wait)
        }
    }
}

let count = 0;
//演示时间是如何频繁发生的
let container = document.querySelector("#container");
function doSomeThing() {
    
    
  //可能会做回调或者ajax请求
  container.innerHTML = count++;
}
let doSome = throttle(doSomeThing,2000,{
    
    
	leading:true,
	trailing:false
});
//给container绑定鼠标移动事件
container.onmousemove = doSome;

猜你喜欢

转载自blog.csdn.net/weixin_52148548/article/details/125191066