防抖和节流在在线预览中的应用

775 阅读4分钟

啥是防抖,啥是节流

    本文的面向对象的不是食堂阿姨的手,也不是新时代钱包里掏不出几个钢镚的平躺人,通过在线预览中的画板的应用,引用出javascript的常见的性能优化场景,同时叙述防抖和节流的区别。

场景引入

    下面给大家展示一下左下方画板是如何在预览中使用,(永中ppt在线h5画板示例演示),大家可以思考下画板该怎么呼出和消失。 1.gif     对上述情况进行拆分一下,正常情况老师们在讲解时候没有操作,预览中应该是无任何操作的按钮: image.png     当有交互性的操作出现,呼出画板,假如通过鼠标的mousemove事件来监听,一但监听到事件,立刻设置画板元素出现。这样老师们就可以进行交互性操作: image.png     那么问题来了,老师想等一段时间后,画板自动消失,听上去不就是setTimeout(隐藏画板,隐藏时间),假设隐藏时间是10s,你在第5秒的时候又移动了鼠标,那么画板是在5s后消失还是存在呢,按照正常的想法,只要移动鼠标,那么画板存在的时间就应该顺延10s,所以最终执行隐藏画板只有一次,也就是哪怕你二十四小时不停的移动鼠标,最终执行隐藏画板的操作只有一次,这就是防抖的一种应用。

防抖

    由上面的案例可以引出防抖的概念:就是指触发事件后在n秒内函数只能执行一次,如果在n秒内又触发了这个事情的话,则会重新计算函数执行时间。

    附上比较经典的防抖函数:

        let content = document.getElementById('cont')
        content.onmousemove = debounce(move,1000);
        function move() {
            console.log('鼠标move')
        }
        function debounce(func, time) {
            let timeout;
            return function () {
                console.log(this)
                let context = this;
                let args = arguments;
                if (timeout) clearTimeout(timeout);
                timeout = setTimeout(() => {
                    func.apply(context, args)
                }, time);
            }
        }

    展示出来的效果如下:

image.png     对于初学者,有几点需要掌握下,function里面的this指的是什么,还有apply的作用是什么,以及timeout变量充当什么角色,please think about,and the answer is behind.

  • this指向就是谁调用的,譬如上面就是cont的dom元素,在上图控制台红色箭头中就可以清晰的看除
  • apply就是改变this的指向并且调用这个函数
  • 闭包

节流

    和防抖不同的是,节流是指在n秒中只执行一次函数,并不像防抖可能很久都不执行一次函数,节流只是为了稀释函数的执行频率。

    附上比较经典的节流函数:

        let content = document.getElementById('cont')
        content.onmousemove = throttle(move,1000);
        function move() {
            console.log('鼠标move')
        }
        function throttle(func, time) {
            let previous = 0;
            return function() {
                let now = Date.now();
                let context = this;
                let args = arguments;
                if (now - previous > time) {
                    func.apply(context, args);
                    previous = now;
                }
            }
        }

那么效果自然就是鼠标move的时候定时打印出鼠标move,那么我在这里提出两个问题:

  1. 如果鼠标离开cont元素,间隔两秒再移动到元素上,控制台会不会立即打印出鼠标move
  2. 上述代码如果不移动,会不会间隔1s打印出鼠标move,如果不行,怎么修改代码?

diss diss diss

不能裤子脱一半,上面的问题还是说一下:

  1. 会,now - previous > 1,所以会立即执行move函数。

image.png 2. 不会打印,怎么去实现,直接上代码(当然这个有点取巧了,哈哈,你还要考虑消除setTimeIntervel定时器,上面是时间戳方法,下面的例子使用settimeout去写的,这个是从度娘上参考的,有兴趣可以多研究研究)。

        let content = document.getElementById('cont')
        content.onmousemove = setTimeIntervel(throttle(move,1000),1000);
        function move() {
            console.log('鼠标move')
        }
        function throttle(func, wait) {
            let timeout;
            return function() {
                let context = this;
                let args = arguments;
                if (!timeout) {
                    timeout = setTimeout(() => {
                        timeout = null;
                        func.apply(context, args)
                    }, wait)
                }

            }
        }

总结

    简而言之,防抖可能你一辈只执行一次,但是节流会按照固定频率执行,以上防抖和节流的函数其实就跟某些算法题一样,不用刻意去记住,但是要理解里面的this指向,闭包等相关的基础概念即可,希望大家有所收获,thanks for your reading。