节流的应用场景
- DOM元素的拖拽功能实现
- 射击游戏
- 计算鼠标移动的距离
- 监听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;