文档章节

Javascript函数节流

waveer
 waveer
发布于 2016/04/28 16:12
字数 1023
阅读 50
收藏 1

最近在做网页的时候有个需求,就是浏览器窗口改变的时候需要改一些页面元素大小,于是乎很自然的想到了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.onresize=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.onresize=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.onresize=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.onresize=throttle(resizehandler,100,200);

image

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


本文转载自:http://www.cnblogs.com/dolphinX/p/3403821.html

waveer
粉丝 0
博文 49
码字总数 5087
作品 0
深圳
程序员
私信 提问
加载中

评论(2)

乌龟壳
乌龟壳
就用定时器不断循环就可以了,每个函数里都用if按照不同的节流逻辑判断,判断通过了才执行真正需要的部分
hision
hision
啥叫函数节流?没看懂,你这个不就是定时执行function
当Flutter遇到节流与防抖

相信web前端的开发者都或多或少的遇到过节流与防抖的问题。函数节流和函数防抖,两者都是优化执行代码效率的一种手段。在一定时间内,代码执行的次数不一定是越多越好。相反,频繁的触发或者...

lunlunshiwo
01/07
0
0
javascript之函数防抖与节流

  平时我们自己在开发过程中可能需要监听窗口的大小(resize等)来调节样式,或者是根据鼠标移动(mousemove等)来执行相应的方法,以及键盘按键(keyup等)事件。但是这里会产生一个问题—...

慕斯不想说话
06/08
0
0
JS执行控制之节流模式实例分析

本文实例讲述了JS执行控制之节流模式。分享给大家供大家参考,具体如下: 节流模式:对重复的业务逻辑进行控制,执行最后一次操作,并取消其他操作,以提高性能。 重复的业务逻辑真的很让人讨...

前端小攻略
2018/12/24
0
0
前端性能优化之Lazyload

@(Mob前端-冬晨)[JavaScript|技术分享|懒加载] [TOC] Lazyload 简介 前端工作中,界面和效果正在变得越来越狂拽炫酷,与此同时性能也是不得不提的问题。有些项目,页面长,图片多,内容丰富。...

idongchen
2018/07/23
0
0
JavaScript函数防抖与函数节流

概念 函数防抖(debounce) 函数防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。 简单的说,当一个动作连续触发,则只执行最后一...

小草先森
01/24
43
0

没有更多内容

加载失败,请刷新页面

加载更多

OSChina 周五乱弹 ——不知道假装开心,装的像么

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @巴拉迪维 :天黑了 你很忧愁, 你说世界上, 找不到四块五的妞, 行走在凌晨两点的马路上, 你疲倦地拿着半盒黄鹤楼。#今日歌曲推荐# 《四块...

小小编辑
今天
2.3K
18
64.监控平台介绍 安装zabbix 忘记admin密码

19.1 Linux监控平台介绍 19.2 zabbix监控介绍 19.3/19.4/19.6 安装zabbix 19.5 忘记Admin密码如何做 19.1 Linux监控平台介绍: 常见开源监控软件 ~1.cacti、nagios、zabbix、smokeping、ope...

oschina130111
昨天
69
0
当餐饮遇上大数据,嗯真香!

之前去开了一场会,主题是「餐饮领袖新零售峰会」。认真听完了餐饮前辈和新秀们的分享,觉得获益匪浅,把脑子里的核心纪要整理了一下,今天和大家做一个简单的分享,欢迎感兴趣的小伙伴一起交...

数澜科技
昨天
34
0
DNS-over-HTTPS 的下一代是 DNS ON BLOCKCHAIN

本文作者:PETER LAI ,是 Diode 的区块链工程师。在进入软件开发领域之前,他主要是在做工商管理相关工作。Peter Lai 也是一位活跃的开源贡献者。目前,他正在与 Diode 团队一起开发基于区块...

红薯
昨天
130
0
CC攻击带来的危害我们该如何防御?

随着网络的发展带给我们很多的便利,但是同时也带给我们一些网站安全问题,网络攻击就是常见的网站安全问题。其中作为站长最常见的就是CC攻击,CC攻击是网络攻击方式的一种,是一种比较常见的...

云漫网络Ruan
昨天
32
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部