{防抖}与{节流}

这不是啥新问题,只不过最近又重新回顾了一下这个问题

一、需求

解决 onscroll每次计算导致的性能问题

onscroll是最典型的需要进行防抖或者节流的处理问题

最近有人问到我,防抖节流有什么不同

二、原理

无论是防抖还是节流最终的目的都是避免回调函数中的处理每次都执行

1、防抖

防抖的思想如下:

  • 借助事件循环队列和setTimeout来实现只有空闲的时候才去处理回调函数
  • 使用setTimeout主要是为了使得处理方法挂在事件循环队列后面,保证事件循环队列中的前面的一些操作有时间进行
// 计时器
var timer = false;
// 
window.onscroll = function(){
    clearTimeout(timer);
    timer = setTimeout(function(){
        console.log("防抖");
        console.log(new Date());
    },300);
};

为什么要clearTimeout

每次onscroll的时候,先清除掉计时器.如果不清楚,会导致多次触发的时候,其实是把好多次的处理方法放在某个时间点后一起执行。

比如下面:

    for (var i = 0; i < 10; i++) {
        (function (i) {
            setTimeout(function () {
                console.log(i);
            }, 3000);
        })(i);
    }

上面代码在3秒后会一起输出 1,2,3,4,5,6,7,8,9

而下面的代码,只会输出9

    var timer2 = false;
    for (var i = 0; i < 10; i++) {
        clearTimeout(timer2);
        (function (i) {
            timer2 = setTimeout(function () {
                console.log(i);
            }, 3000);
        })(i);
    }

这是因为,每次我将上次的timer给清除掉了,也就是我如果后面同样有处理函数的话,那我就用后面的定时器。

前面定时器没啥用了,所以直接clearTimeout保证了这种实现。

在解决onscroll问题的时候,如果自己观察console可以发现,防抖保证了滚动停止的时候,才会进行处理,因为滚动停止了,没有scroll事件了,最后一次timer会被保留,从而进行调用

2、节流

节流思想如下:

  • 借助flag元素和setTimeout实现在一定时间内,只执行一次方法

防抖中,每次其实都会生成定时器,只不过定时器还没到时间(这个时间是指将事件挂在事件循环队列后面的时间),就把上面的定时器给清掉了。

而节流则是到了一定的时间,我才进行定时器,否则我不进行定时器。

比如:

var flag = true;

window.onscroll = function(){
    if(!flag) return false;
    flag = false;
    setTimeout(function(){
        console.log("节流" + new Date());
        flag = true;
    },300);
};

这个还是比较直观的:

  • 首先有一个标志位flag,默认是true,这个标志位控制是否能够进行定时器.
  • 如果 flag 是 false,则之间返回,表示时间还没到,不能进行下一次定时器
  • 如果 flag 是 true,说明能够进行一次处理,首先会将 flag 标志位置为 false,表示已经执行过一次
  • 在定时器中,处理方法操作外,最后一条语句flag = true 表示,本段时间已经结束了,可以进行下一次的定时器。

产生的效果如下:

第一次执行定时器后,300毫秒后,将事件挂在事件循环队列后,而在这个过程中,(包括300ms及事件循环队列循环到挂上事件的时间段)flag 都是 false,则不会多次设置定时器,一旦事件执行了,则 flag 变成 true,能够设置下一次定时器

下面的代码虽然无法做到节流(不是无法做到节流,for太快了,和onscroll是不一样的),但是可以明显的看到一个等待期

并且最后只能输出一个0,因为第一次执行之后,由于for太快,在等待(等待概念查看上面的解释)的时间中,for已经结束了。

    var flag = true;
    for (var i = 0; i < 1000; i++) {
        if (!flag) {
            console.log("等待期");
            continue;
        }
        flag = false;
        (function (i) {
            setTimeout(function () {
                console.log(i);
                flag = true;
            }, 0);
        })(i);
    }

三、实例

1、防抖解决onscroll实例

示例中每次滚动结束后才会触发一次alert

http://jsrun.net/VviKp/edit?utm_source=website

2、节流解决onscroll实例

如果较长点时间快速滚动不停下,会执行两次,这就是节流的周期。

http://jsrun.net/8viKp/edit?utm_source=website

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏崔庆才的专栏

只会用Selenium爬网页?Appium爬App了解一下

3.6K5
来自专栏极客慕白的成长之路

Atom主题插件美化教程

对应的Themes就是可更换的主题。在这一共分为两块,UI Theme和Syntax Theme,一个是UI的,一个是文件语法的,这里可以选择相应的主题。

2392
来自专栏Web 开发

ubuntu学习手札——架设LAMP服务器

简单介绍一下,LAMP就是Linux + Apache + Mysql + Php,现在的服务器大部分都是基于这种方式架设的,我们这里的Linux就是ubunt...

1051
来自专栏技术博客

ExtJs十一(ExtJs Mvc图片管理之一)

图片管理要在两个地方使用:一是标签页内的图片管理,一是文章内容编辑时嵌套到插入图片的窗口内。因而,将图片管理做成一个扩展比较方便。当然,做成MVC模式也行,不争...

1443
来自专栏smy

微信小程序避坑指南

 详见官方文档:https://developers.weixin.qq.com/miniprogram/dev/framework/client-lib/cl...

5133
来自专栏DeveWork

Web 前端性能优化相关内容解析

Web 前端性能优化相关内容,来源于《Google官方网页载入速度检测工具PageSpeed Insights 使用教程》一文中PageSpeed Insigh...

26610
来自专栏我和PYTHON有个约会

Django来敲门~第一部分【8.网页中的css/js/image处理】

通常情况下,网页开发时,页面中的样式是通过外部css样式进行处理的,外部的css文件加载在Django中,需要进行简单的处理

812
来自专栏salesforce零基础学习

salesforce零基础学习(七十四)apex:actionRegion以及apex:actionSupport浅谈

我们在开发中,很难会遇见不提交表单的情况。常用的apex:commandButton,apex:commandLink,apex:actionFunction,...

2767
来自专栏GreenLeaves

Fiddler4抓包工具使用教程一

本文参考自http://blog.csdn.net/ohmygirl/article/details/17846199,纯属读书笔记,加深记忆 1、抓包工具有很...

81710
来自专栏FreeBuf

CIA机密文档追踪工具Scribbles详细分析

2017年4月28日,维基解密发布了CIA“涂鸦”(Scribbles)项目的文档和源代码(参考地址1)。这是一个文档预处理系统,用于给涉密文档打上“Web b...

2837

扫码关注云+社区

领取腾讯云代金券