moyan's life

vuePress-theme-reco moyanfaker    2017 - 2021
moyan's life moyan's life

Choose mode

  • dark
  • auto
  • light
Home
Category
  • ES6
  • 闭包
  • js的未来
  • 数组
  • Typescript
  • 函数式编程
  • 防抖和节流
Tag
TimeLine
Docs
  • vuepress-reco
Contact
  • GitHub
author-avatar

moyanfaker

12

Article

12

Tag

Home
Category
  • ES6
  • 闭包
  • js的未来
  • 数组
  • Typescript
  • 函数式编程
  • 防抖和节流
Tag
TimeLine
Docs
  • vuepress-reco
Contact
  • GitHub

防抖和节流的实现

vuePress-theme-reco moyanfaker    2017 - 2021

防抖和节流的实现

moyanfaker 2020-12-19 防抖和节流js

# 防抖和节流的实现

img

云生流长 2019-05-14 15:04:32 img 1739 img 收藏 22

分类专栏: JavaScript

版权

# 1.防抖(debounce)

常见的滚动监听事件,每次滚动都会触发,如此太过浪费性能,要如何优化呢?

思路:在第一次触发事件的时候,不是立即执行函数,而是给出一个delay时间值,例如200ms

  • 如果在200ms内没有再次触发该事件,则执行函数
  • 如果在200ms内有再次触发事件,则清除当前的计时器,重新开始计时器

效果:短时间内大量出发同一事件最终只会执行一次

实现:利用setTimeOut来实现计时器的功能

 // 防抖
        const debounce = (fn, delay) => {
            /**
             * @param [Function] fn 需要使用防抖的函数
             * @param [Number] delay 毫秒,防抖期限值
            */
            let timer = null
            return () => {
                if (timer) {
                    // 进入此分支说明:当前正在一个计时周期中,并且再次触发了事件,取消当前计时,重新开始计时
                    clearTimeout(timer)
                }
                // 进入此分支说明:当前没有计时,则开始新的计时
                timer = setTimeout(fn, delay)
            }
        }
​
        const showTop = () => {
            let scrollTop = document.body.scrollTop || document.documentElement.scrollTop
            console.log('当前位置:' + scrollTop)
        }
        window.onscroll = debounce(showTop, 1000)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

定义:短时间内连续触发的事件,防抖可以让在某个时间期限内事件函数只执行一次

# 2.节流(throttle)

需求:即使用户不断拖动滚动条,也可以在某个时间间隔后给出反馈?

思路:设计一种类似“青蛙”的函数,即让函数执行一次后,在某个时间段内暂时失效(冬眠),等过了这个时间段再重新激活(苏醒)

效果:短时间内大量触发同一事件,函数执行一次之后在某个指定的时间内不再执行,直到过了这个指定的时间才会重新生效

实现:状态位 / 时间戳 / setTimeout 标记

// 方案一:状态位
        const throttle = (fn, delay) => {
            /**
             * @param [Function] fn 需要使用防抖的函数
             * @param [Number] delay 毫秒,防抖期限值
            */
            let valid = true
            return () => {
                if (!valid) {
                    return false
                }
                // 执行函数+把状态位设置为无效
                valid = false
                setTimeout(() => {
                    fn()
                    valid = true
                }, delay)
            }
        }
​
        const showTop = () => {
            let scrollTop = document.body.scrollTop || document.documentElement.scrollTop
            console.log('当前位置:' + scrollTop)
        }
        window.onscroll = throttle(showTop, 1000)

// 方案二:时间戳
        const throttle = (fn, delay) => {
            /**
             * @param [Function] fn 需要使用防抖的函数
             * @param [Number] delay 毫秒,防抖期限值
            */
            let start
            return () => {
                let now = Date.now()
                if (!start) {
                    start = now
                }
​
                if (now - start >= delay) {
                    fn()
                    start = null
                }
            }
        }
​
        const showTop = () => {
            let scrollTop = document.body.scrollTop || document.documentElement.scrollTop
            console.log('当前位置:' + scrollTop)
        }
        window.onscroll = throttle(showTop, 1000)

// 方案三:setTimeout标记
        const throttle = (fn, delay) => {
            /**
             * @param [Function] fn 需要使用防抖的函数
             * @param [Number] delay 毫秒,防抖期限值
            */
            let timer = null
            return () => {
                if (!timer) {
                    timer = setTimeout(() => {
                        fn()
                        timer = null
                    }, delay)
                }
            }
        }
​
        const showTop = () => {
            let scrollTop = document.body.scrollTop || document.documentElement.scrollTop
            console.log('当前位置:' + scrollTop)
        }
        window.onscroll = throttle(showTop, 1000)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74

# 3.防抖和节流的区别?

防抖:短时间内多次触发,最终在停止触发后的某个指定时间执行一次函数————只执行一次

节流:短时间内多次触发,即使触发仍在继续也可以根据指定时间触发一次函数————至少执行一次