js 节流防抖

247 阅读2分钟

闭包、防抖、节流、input搜索、窗口计算、图片懒加载

  • 防抖debounce

    • 当持续触发事件,一定时间内没有再触发事件,事件处理函数才会执行一次;如果设定的时间到来之前,又一次触发了事件,就重新开始延时

    • input输入搜索

      // timer变量需要一直保存在内存当中,内存的泄露,用闭包来实现
      function debounce(delay) {
      	let timer
      	return function(value) {
      		clearTimeout(timer)
      		timer = setTimeout(() => {
      			console.log(value)
      		}, delay)
      	}
      }
      // 如果这里不这样写,而是在keyup的callback中调用debouce()()就没有意义了
      // 定义无数timer
      var debounceFunc = debounce(1000)
      input.addEventListener('keyup', function(e) {
      	debounceFunc(e.target.value)
      })
      
      // react中
      
      handleChangeCallback = (args) => {
      	const value = args[0]
      	if (value.trim() === '') {
      		console.log(value)
      	} else {
      		console.log(value)
      	}
      }
      debounceFunc = debounce(this.handleChangeCallback, 500)
      handleChange = (e) => {
      	this.debounceFunc(e.currentTarget.value)
      }
      
      <Input onChange={this.handleChange} />
      
    
    function debounce(delay, fn) {
    	let timer
    	return function() { // 箭头函数没有argument
    		var args = arguments
    		clearTimeout(timer)
    		timer = setTimeout(() => {
    			fn(args)
    		}, delay)
    	}
    }
    
    // 有返回值
    function debounce(func, wait) {
        var timeout, result;
        return function () {
            var args = arguments;
            clearTimeout(timeout)
            timeout = setTimeout(() => {
                result = func(args)
            }, wait);
            return result
        }
    }
    
  • 节流throttle

    • 一段时间内只做一件事情

    • 例子

      		const button = document.getElementById('button')
      		function thottle(delay, fun) {
              let timer
              return function () {
                let args = arguments
                if (!timer) {
                  timer = setTimeout(() => {
                    fun(args)
      							// timer如果不赋值为null不会因为执行完而自动变为null的
                    timer = null
                  }, delay)
                }
              }
            }
            handleClick = () => {
              console.log(111)
            }
            let thottleFun = thottle(1000, handleClick)
            button.addEventListener('click', () => {
              thottleFun()
            })
      			// 如果下面这种写法可以直接调用thottle
            // button.onclick = thottle(1000, handleClick)
      			// 这样写也可以,因为相当于回调函数直接是debounce函数
      			// button.addEventListener('click', debounce(1000, handleClick))
      			// addEventListener监听某个事件,只要发生这个事件就会执行回调函数
      			// 这个回调函数本身,不会执行多次	
      			
      
    • 图片懒加载

      			var img = document.getElementsByTagName('img')
            var num = img.length
            var n = 0 // 存储图片加载到的位置,避免每次都从第一张图片开始便利
            var _clientHeight = document.documentElement.clientHeight // 可见去遇高度
            var _scrollTop =
              document.documentElement.scollTop || document.body.scrollTop // 滚动条距顶部高度
            // 监听窗口变化重新计算可视区域
            function computedClientHeight() {
              _clientHeight = document.documentElement.clientHeight // 可见区域高度
            }
      
            // 页面载入完毕加载可视区域内的图片
            lazyload()
            function lazyload() {
              // 获取滚动条距离顶部高度
              _scrollTop =
                document.documentElement.scrollTop || document.body.scrollTop
              for (var i = n; i < num; i++) {
                console.log(img[i].offsetTop)
                if (img[i].offsetTop < _scrollTop + _clientHeight) {
                  if (img[i].getAttribute('src') === '') {
                    img[i].src = img[i].getAttribute('data-src')
                  }
                  n = i + 1
                }
              }
            }
      
            // 使用节流函数实现性能较好的懒加载
            window.addEventListener('scroll', throttle(lazyload, 100))
      
            // 使用防抖函数优化不断出发的窗口变化
            window.addEventListener('resize', debounce(800, computedClientHeight))
            function debounce(delay, fn) {
              let timer
              return function () {
                // 箭头函数没有arguments
                var args = arguments
                clearTimeout(timer)
                timer = setTimeout(() => {
                  fn(args)
                }, delay)
              }
            }
            function throttle(fn, delay) {
              let timer
              return function () {
                if (!timer) {
                  timer = setTimeout(() => {
                    fn()
                    timer = null
                  }, 1000)
                }
              }
            }
      
    function throttle(fn, delay) {
    	let timer
    	return function() {
    		if (!timer) {
    			timer = setTimeout(() => {
    				fn()
    				timer = null
    			}, 1000)
    		}
    	}
    }