函数节流的原理

函数节流,就是对会频繁触发的函数事件做一些限制,让这些函数可以在每隔一定的时间或者每次满足一定的条件下再触发。一般我们会给他起一个名字throttle。也就是节流的意思。一般这样的函数有 resize事件、ontouchmove事件等。

举个简单的例子

<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>测试函数节流</title>
<style>
#container{
width: 100%;
height: 200px;
border: 1px solid #646464;
color: #000000;
}
</style> </head>
<body >
<div id="container"></div>
</body>
<script>
function alertSomething(){
alert("您的鼠标正在移动");
};
document.getElementById("container").onmousemove = alertSomething;
</script>
</html>

上面的代码就是简单的渲染出来一个div 然后给这个div绑定了一个鼠标移动事件。但是我们在实际情况下,这种体验是不好的,因为这个事件会被十分频繁的触发。只要我们在这个div上移动鼠标就会弹出这个阻塞性的事件alert,所以我们希望每隔一定时间提醒一下“您的鼠标正在移动”。
下面写一个节流的函数throttle()

function throttle(func){
var timer;
return function(){
var context = this;
var args = arguments;
clearTimeout(timer);
timer = setTimeout(function(){
func.apply(context,args);
},1000);
} }

然后我们修改一下页面上的代码:

<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>测试函数节流</title>
<style>
#container{
width: 100%;
height: 200px;
border: 1px solid #646464;
color: #000000;
}
</style> </head>
<body >
<div id="container"></div>
</body>
<script> function throttle(func){
var timer;
return function(){
var context = this;
var args = arguments;
clearTimeout(timer);
timer = setTimeout(function(){
func.apply(context,args);
},1000);
} }
function alertSomething(){
alert("您的鼠标正在移动");
}; document.getElementById("container").onmousemove = throttle(alertSomething);
</script>
</html>

下面我仔细解释一下这个节流函数。

函数利用闭包的形式存储了一个timer定时器变量,说实话我刚开始看别人在写这个节流函数的时候,也是不太容易懂,只是马马虎虎觉得是这样的,直到我亲自实现一遍,才明白。在这里建议亲自动手,丰衣足食~~

这个timer变量当然也可以写在全局作用域中,但是可能会跟全局作用域中的变量产生冲突,所以在这里用闭包的形式来提供,防止它污染全局作用域。(看好多人在这里用“污染”,我想可能是如果有很多像timer这样的变量都放在全局作用域中,到时候肯定容易与在全局作用域中常用的变量混淆。因为它毕竟只是在这个节流函数做定时器使用)。

然后就是throttle函数返回的函数了。在这个函数中,要保存好传进来的执行上下文this,和参数arguments。应为我们要注意的是setTimeout()函数中作用域是全局的,也就是setTimeout中的this指的是window在这里这个执行上下文其实就是container对象,传入的参数就是鼠标移动这个事件的所有信息我们将这个container这个对象的鼠标移动事件函数重写成alertSomething这个函数。同时鼠标移动事件的信息也作为参数传入进去这一点也是我打印出他的相应信息后才恍然大悟,可能平时我们会理所当然的知道就是这样子的,但是为什么会这样子呢,我们知道了alertSomething这个函数的参数和执行上下文是怎么传进去的,那直接调用elementobj.onmousemove=function(){xxxxxx}这个函数的时候,上下文和参数是怎么传入进去的也应该是这样的原理吧。这是我的个人理解。

明白了上面的基本原理,我们再梳理一下节流函数发挥作用的过程:第一次调用这个节流函数的时候也就是第一次触发鼠标移动事件的时候,timer是没有的,所以clearTimeout(timer)清理的定时器也是没有的,但是等第二次触发鼠标移动事件的时候,鼠标移动事件的处理函数就是一直是throttle返回的函数了。首先会清理掉上次调用的时候的定时器,然后重新设置一个定时器。每次鼠标移动都是这样的处理过程,直到鼠标不再移动一秒钟后,定时器中的函数才被使用。

总之仔仔细细理解一下这个过程感觉真好!

但是如果我们需要自定义延迟的事件的话怎么办呢,下面我们可以再改进一下:

function throttle(func,delay){
var timer;
return function(){
var context = this;
var args = arguments;
clearTimeout(timer);
timer = setTimeout(function(){
func.apply(context,args);
},delay);
} }
function dealMouseMove(){
alert("您的鼠标正在移动");
};
document.getElementById("container").onmousemove = throttle(dealMouseMove,500);

在这里感谢 Toobugflowmemo 两位大神的指正,上面函数的功能更应该称之为debounce,也即是消除抖动的意思。前端技术中常用的throttle相当于一个频率控制器,让一段时间内快速触发很多次的事件处理程序可以只触发一定的次数, 而debounce不只是减少了触发次数,而且要满足一定的条件下才会触发。两者实现方法都是差不多的,叫法不一样而已,不能将两者割裂开来。

可以参考的相关网址:http://www.css88.com/archives/4648
可以参考的相关网址:http://www.alloyteam.com/2012/11/javascript-throttle/

JavaScript中函数节流的理解的更多相关文章

  1. JavaScript 中函数节流和函数去抖的讲解

    JavaScript 中函数节流和函数去抖的讲解 我们都知道频繁触发执行一段js逻辑代码对性能会有很大的影响,尤其是在做一些效果实现方面,或者逻辑中需要进行后端请求,更是会导致卡顿,效果失效等结果,所 ...

  2. Javascript中函数的四种调用方式

    一.Javascript中函数的几个基本知识点: 1.函数的名字只是一个指向函数的指针,所以即使在不同的执行环境,即不同对象调用这个函数,这个函数指向的仍然是同一个函数. 2.函数中有两个特殊的内部属 ...

  3. JavaScript中函数是不能重载原因

    以前有一次写JS插件的时候,由于后台写习惯了,妄想在JS中写重载函数,可惜不能成功,原因花了一点时间记了下来 首先要理解重载的含义:函数返回值不同或者形式参数个数不同但函数名相同的函数 JavasSc ...

  4. JavaScript中函数作为另一个函数的参数的时候它存在于哪个作用域

    一直对函数作为参数被传递进另外一个函数理解的不是很清除.先看下这段代码吧: function test(fn){ var bar = 1; fn(); } var bar = 99; test(fun ...

  5. JavaScript中函数函数的定义与变量的声明<基础知识一>

    1.JavaScript中函数的三种构造方式 a.function createFun(){ } b.var createFun=function (){ } c.var createFun=new ...

  6. JavaScript中函数的形参和实参的实现原理剖析

    我们都知道JS里面参数的传递是可以不一样的,比如我们有一个函数: <script type="text/javascript"> function one(a,b,c) ...

  7. JavaScript中函数的调用

    JavaScript中函数的调用 制作人:全心全意 在JavaScript中,函数定义后并不会自动执行,要执行一个函数需要在特定的位置调用该函数,调用函数需要创建调用语句,调用语句包含函数名称和参数. ...

  8. JavaScript中函数的定义

    JavaScript中函数的定义 制作人:全心全意 在JavaScript中,函数是由关键字function.函数名加一组参数以及置于大括号中需要执行的一段代码定义的.定义函数的基本语法格式如下: f ...

  9. javascript中函数声明、变量声明以及变量赋值之间的关系与影响

    javascript中函数声明.变量声明以及变量赋值之间的关系与影响 函数声明.变量声明以及变量赋值之间有以下几点共识: 1.所有的全局变量都是window的属性 2.函数声明被提升到范围作用域的顶端 ...

随机推荐

  1. k8s-ingress部署测试以及深入理解

    1.ingress 部署有两种方式.本次采用DaemonSet部署. apiVersion: v1 kind: Namespace metadata: name: ingress-nginx --- ...

  2. JZ-039-平衡二叉树

    平衡二叉树 题目描述 输入一棵二叉树,判断该二叉树是否是平衡二叉树. 在这里,我们只需要考虑其平衡性,不需要考虑其是不是排序二叉树 题目链接: 平衡二叉树 代码 /** * 标题:平衡二叉树 * 题目 ...

  3. 二级py--day4 数据结构与算法篇

    二级py--day4 数据结构与算法篇 1.算法的基本特征:可行性.确定性.有穷性.拥有足够的情报 2.算法的设计要求包括效率与低存储量,既要考虑算法的时间复杂度和空间复杂度 3.算法的优劣:与算法描 ...

  4. java IO流体系--通识篇

    1.I/O流是什么 Java的I/O流是实现编程语言的输入/输出的基础能力,操作的对象有外部设备.存储设备.网络连接等等,是所有服务器端的编程语言都应该具备的基础能力. I = Input(输入),输 ...

  5. 微信小程序token失效 自动请求后端,适用于自动登录

    app.js // app.js App({ onLaunch() { let token = wx.getStorageSync('token') if (!token) { wx.login({ ...

  6. laravel 解决跨域问题并封装到中间件

    larav 官方手册有详细的步骤 https://learnku.com/articles/6504/laravel-cross-domain-solution 我们在用 laravel 进行开发的时 ...

  7. 微信小程序表单验证(WxValidate使用)

    参考博客: https://www.cnblogs.com/zhangxiaoyong/p/10166951.html https://github.com/wux-weapp/wx-extend/b ...

  8. laravel 5.6 API 接口开发限制接口访问频率

    在laravel 5.6及以上版本中框架中已自带ThrottleRequests,但是为了更好的处理消息,我们可以再新加一个中间件,来更方便的处理相应信息 第一步: php artisan make: ...

  9. ArcGIS修路问题(最优路径问题)

    1 前言 修路问题,辅助减少花费.用栅格进行路径分析. 2 问题阐述 根据题目要求,找出一条从学校通往某目的地的道路,实现以下操作: (1)坡度在30度以上的地形不适合修建道路,适合修路的坡度相等间隔 ...

  10. OpenSSL CVE-2022-0778漏洞问题复现与非法证书构造

    本文介绍CVE-2022 0778漏洞及其复现方法,并精心构造了具有一个非法椭圆曲线参数的证书可以触发该漏洞. 本博客已迁移至CatBro's Blog,那是我自己搭建的个人博客,欢迎关注.本文链接 ...