【javascript】滚动条事件优化->函数节流与去抖

为啥题目这样写,因为之前绑定滚动调试事件我是这样写的:

element.addEventListener('scroll', function() {
    // do something
})

想过要优化这个,因为滚动事件,会触发很多次,里面的逻辑过于复杂,那么会很占用浏览器资源。但是不知道从何优化。

直到看到《JS高程》的函数节流,滚动条和事件和resize操作,是同样的道理,实际上我们需要做的操作只需要在滚动条事件完成或者resize的操作完成的一瞬间去执行我们的逻辑,中间的过程,我们的逻辑处理是没有意义的,因为它只是一个中间状态。

定义这样一个对象:

  var processor = {
    timeoutId: null,
    //实际执行的代码
    performProcessing: function(){
      console.log('performProcessing 方法, 你的处理逻辑')
      console.log('hello word')
    },
    //初始处理调用的方法
    process: function() {
      console.log('process方法')
      clearTimeout(this.timeoutId)
      var that = this
      this.timeoutId = setTimeout(function(){
        that.performProcessing()
      }, 100)
    }
  }

我们在绑定滚动条事件可以这样:

  window.onscroll = function(){
    processor.process()
  }

《JS高程3》上面用的是throttle节流来命名方法解决,但是按照lodash 和underscore 都是用的debounce防抖来解决这个问题。我们不纠结这个问题。先看《JS高程3》最后的封装方法

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

我们绑定一个滚动条滚动事件,并且指定我们的处理逻辑->print函数:

   function print() { console.log('scroll handle logic') }
   window.onscroll = function() { throttle(print) } 

好到了这一步,我们已经能够解决类似的问题了,像scroll 和 resize事件的话,这类事件,实际上我们只需要最后一次去触发,不然我们scroll事件触发了100次,每次都得触发是不行的,只需要最后一次去触发。上面的函数实际上是利用定时器,比如我们1s之内连续触发了100次,我们每执行到throttle函数回去检查,print方法的tId是否存在,也就是上一个定时器是否存在,如果存在,则清除,连续的过程中,只要100ms内的连续操作,前面的定时器是被取消了的,最后一次没有被取消,在最后一次的事件触发的100ms之后会触发。(O__O …,大概就是这样,希望没搞晕你)


throttle 节流 和 debounce 防抖

lodash 和 underscore给我们提供了这些方法的扩展,并且有更多功能。

在resize 和 scroll 以及 ,防止用户重复点击提交数据,检查用户输入的数据(ajax请求) 都可以用到debounce防抖,这些操作只需要最后一次(或者第一次)的事件被触发。

在检测用户是否要滑动到页面底部(加载更多数据),这种情况需要用到throttle 节流,每隔多少时间去触发事件。

权威参考:

https://css-tricks.com/debouncing-throttling-explained-examples/

lodash的 debouncethrottle

underscore的 debouncethrottle


example(in vue):
比如有一个input,我们的需求是将用户输入的英文字母变成大写的,代码长下面这样,
function里面的实际上可以换成请求服务器,检查名字是否重复等操作。

<input type="button" v-model="name" @keyUp="upperName"/>
import { debounce } from 'lodash'
export default {
    data () {
        return {
            name: ''
        }
    },
    methods: {
        upperName: debounce(function(){
            if(isString(this.name)) { this.name = this.name.toUpperCase() }
        }, 100),
    }
} 
posted on 2017-08-30 15:25  狂奔的冬瓜  阅读(960)  评论(0编辑  收藏  举报