当前位置: 首页 > news >正文

Javascript 函数节流

最近在做网页的时候有个需求,就是浏览器窗口改变的时候需要改一些页面元素大小,于是乎很自然的想到了window的resize事件,于是乎我是这么写的

复制代码
<!DOCTYPE html>
<html>
<head>
    <title>Throttle</title>
</head>
<body>
    <script type="text/javascript">
        n=0;
        function resizehandler(){
            console.log(new Date().getTime());
            console.log(++n);
        }

        window.οnresize=resizehandler;
    </script>
</body>
</html>
复制代码

 

功能倒是实现了,但是我拖拽的方式改变浏览器窗口大小的时候看了下控制台

image

 

没错,简单的一个拖拽让我的resizeHandler()方法执行了52次,这完全不是我想要的效果,实际上我的resizeHandler()方法的代码很复杂,甚至会使用ajax向服务器发送请求,要是简单的一次改变窗口大小就要调用52次这还了得

函数节流

其实我的本意只是窗口resize后页面做一些调整就可以,而window的resize事件并不是在resize结束后才触发的,具体则么个频率我也不知道,但却是在不停的调用,直到窗口大小不再变化。其实类似的机制还有鼠标的mousemove,都是在短时间内重复触发。

在《JavaScript高级程序设计》中有专门应对此问题的函数节流

function throttle(method,context){
            clearTimeout(method.tId);
            method.tId=setTimeout(function(){
                method.call(context);
            },500);
        }

原理很简单,利用定时器,让函数执行延迟500毫秒,在500毫秒内如果有函数又被调用则删除上一次调用,这次调用500毫秒后执行,如此往复。这样我刚才的代码可以改为

复制代码
<script type="text/javascript">
        n=0;
        function resizehandler(){
            console.log(new Date().getTime());
            console.log(++n);
        }

        function throttle(method,context){
            clearTimeout(method.tId);
            method.tId=setTimeout(function(){
                method.call(context);
            },500);
        }

        window.οnresize=function(){
            throttle(resizehandler,window);
        };
    </script>
复制代码

拖拽一下试试,果真只执行了一次

image

另一种做法

网上还有一种函数节流方案,它是这么做的

复制代码
function throttle(method,delay){
            var timer=null;
            return function(){
                var context=this, args=arguments;
                clearTimeout(timer);
                timer=setTimeout(function(){
                    method.apply(context,args);
                },delay);
            }
        }
复制代码

调用一下试试,一样的效果

复制代码
<script type="text/javascript">
        n=0;
        function resizehandler(){
            console.log(new Date().getTime());
            console.log(++n);
        }

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

        }

        window.οnresize=throttle(resizehandler,500);//因为返回函数句柄,不用包装函数了
    </script>
复制代码

image

比较

两种方法都是利用了setTimeout,不同的是第二种方法加入的函数延迟执行时间,这个在第一种方案中很容易也具有此功能,加一个参数的事儿。

但第一种方案把tId设为函数的一个变量保存,而第二种创建了一个闭包来存储。个人觉得差距不大,很喜欢第一种,简单,高效。

新需求

有一天做了个类似的东西,就像百度首页输入自动提示一样的东西,我在text上绑定keyup事件,每次键盘弹起的时候自动提示,但是又不想提示那么频繁,于是我用了上面方法,但是悲剧了,只有停止输入等500毫秒才会提示,在输入过程中根本就没有提示。看了一下代码,可不是嘛,只要是用户会盲打,在500毫秒内按一下键盘,提示函数就会不断被延迟,这样只有停下来的时候才会提示,这就没意义了。

能不能在函数节流的基础上间隔固定时间就执行一次?

小改动

在网上搜了一下我们可以根据第二种写法(第一种为函数拓展多个变量感觉有些不好)做些改动,添加一个参数作为到固定间隔必须执行

复制代码
function throttle(method,delay,duration){
            var timer=null, begin=new Date();
            return function(){
                var context=this, args=arguments, current=new Date();;
                clearTimeout(timer);
                if(current-begin>=duration){
                     method.apply(context,args);
                     begin=current;
                }else{
                    timer=setTimeout(function(){
                        method.apply(context,args);
                    },delay);
                }
            }
}
复制代码

这样每次我们判断间隔了多久,要是超过设置时间则立即执行一次,以刚才例子试一试效果

window.οnresize=throttle(resizehandler,100,200);

image

果真既没有频繁执行也没有就最后执行

转载于:https://www.cnblogs.com/chenqiushi/p/3986354.html

相关文章:

  • 利用python做数据分析(六)-reindex
  • GitHub 小试
  • Actor模式的弊端
  • 广告
  • 自学的IT程序员通常缺少哪些技能
  • IOS中获取各种文件的目录路径的方法
  • 怎么样抢注新域名
  • 北京实习面试总结,四天面试6个公司,有所收获。
  • 关于未来编程语言的预测
  • Spark Graphx编程指南
  • 找回HDFS corrupted文件残留数据
  • Oracle 执行计划(Explain Plan)
  • MSSQL2008-2012数据库的字段类型整理
  • Vector的一种实现(二)
  • 前端导出Excel兼容写法
  • ES6指北【2】—— 箭头函数
  • 【JavaScript】通过闭包创建具有私有属性的实例对象
  • 【附node操作实例】redis简明入门系列—字符串类型
  • EOS是什么
  • spring学习第二天
  • ViewService——一种保证客户端与服务端同步的方法
  • vue总结
  • 多线程 start 和 run 方法到底有什么区别?
  • 关于 Cirru Editor 存储格式
  • 开放才能进步!Angular和Wijmo一起走过的日子
  • 看图轻松理解数据结构与算法系列(基于数组的栈)
  • 模型微调
  • 漂亮刷新控件-iOS
  • 一道面试题引发的“血案”
  • 怎么将电脑中的声音录制成WAV格式
  • 机器人开始自主学习,是人类福祉,还是定时炸弹? ...
  • ###C语言程序设计-----C语言学习(3)#
  • #vue3 实现前端下载excel文件模板功能
  • #设计模式#4.6 Flyweight(享元) 对象结构型模式
  • $(document).ready(function(){}), $().ready(function(){})和$(function(){})三者区别
  • $分析了六十多年间100万字的政府工作报告,我看到了这样的变迁
  • (2021|NIPS,扩散,无条件分数估计,条件分数估计)无分类器引导扩散
  • (delphi11最新学习资料) Object Pascal 学习笔记---第5章第5节(delphi中的指针)
  • (七)理解angular中的module和injector,即依赖注入
  • (学习日记)2024.03.12:UCOSIII第十四节:时基列表
  • (转)平衡树
  • (转)为C# Windows服务添加安装程序
  • .NET 依赖注入和配置系统
  • .NET多线程执行函数
  • [1127]图形打印 sdutOJ
  • [Android]使用Android打包Unity工程
  • [BZOJ] 2006: [NOI2010]超级钢琴
  • [C++]:for循环for(int num : nums)
  • [CISCN2019 华东南赛区]Web4
  • [codeforces]Checkpoints
  • [Contest20180313]灵大会议
  • [c语言]小课堂 day2
  • [HOW TO]怎么在iPhone程序中实现可多选可搜索按字母排序的联系人选择器
  • [leetcode 数位计算]2520. 统计能整除数字的位数
  • [Linux] 用LNMP网站框架搭建论坛