前端日常开发常用功能系列之节流

这是前端日常开发常用功能这个系列文章的第一篇,该系列是日常开发中一些常用的功能的再总结、再提炼,以防止遗忘,便于日后复习。该系列预计包含以下内容: 防抖、节流、去重、拷贝、最值、扁平、偏函数、柯里、惰性函数、递归、乱序、排序、注入、上传、下载、截图。。。

 什么是节流?

节流就是如果你持续触发事件,每隔一段时间,只执行一次事件。

为什么要进行节流?

在频繁触发事件的场景,有些情况可能执行的逻辑比较复杂或者耗时,此时浏览器的处理跟不上触发,就会发生卡顿、假死或者事件堆积,为了解决这个故障,节流是其中之一的策略,前文还有另一种策略的介绍: 防抖。

常见的需要防抖的场景: 搜索框keyup、keydown等触发后台请求; 频繁改变窗口大小resize;鼠标移动mousemove事件;类似以上频繁触发并且处理逻辑较为耗时或者触发时需要请求后台接口;

如何做到节流呢?

版本1,设定间隔,如果当前请求触发时间和上次触发间隔小于设定间隔,则不触发

<html>
<head>
<meta charset="UTF-8">
<style>
    div {
         500px;
        height: 300px;
        background: orange;
    }
</style>
</head>
<body>
    <div id="div"></div>
</body>
<script>
    const div = document.getElementById('div');


    const throttle = (fn, wait) => {
        let pre = 0, context, args;

        return function() {
            context = this;
            args = arguments;
            const now = new Date().getTime();
            if(now -pre > wait) {
                fn.apply(context, args);
                pre = now;
            }
        }
    };

    const fn = throttle((e) => {
        console.log('move', e);
    }, 1000)

    div.addEventListener('mousemove', fn);
</script>
</html>

执行结果是: 当鼠标不断在橙色区域移动,则每隔1s才会打印‘move';(设定的间隔就是1000ms)但是在结尾处不会执行事件,比如4.5s结束则事件只在0s、1s、2s、3s、4s执行

版本2,使用定时器;首次触发设定新的定时器,如果间隔小于预设,则清除旧的定时器;

<html>
<head>
<meta charset="UTF-8">
<style>
    div {
         500px;
        height: 300px;
        background: orange;
    }
</style>
</head>
<body>
    <div id="div"></div>
</body>
<script>
    const div = document.getElementById('div');

    const throttle = (fn, wait) => {
        let context, args, timer;

        const run = () => {
            timer = setTimeout(() => {
                fn.apply(context, args);
                clearTimeout(timer);
                timer = null
            }, wait);
        }

        return function() {
            context = this;
            args = arguments;
            if(!timer) {
                run();
            }
        }
    };

    const fn = throttle((e) => {
        console.log('move', e);
    }, 1000)

    div.addEventListener('mousemove', fn);
</script>
</html>

执行结果是:当鼠标不断在橙色区域移动,则每隔1s才会打印‘move',但是和非定时器版本的区别在于此版本第一次执行也是在1s之后,并非立即执行

如果我们想在首次触发事件时立即执行一次,在事件触发结束后再执行一次应该怎么办呢?

版本3

<html>
<head>
<meta charset="UTF-8">
<style>
    div {
         500px;
        height: 300px;
        background: orange;
    }
</style>
</head>
<body>
    <div id="div"></div>
</body>
<script>
    const div = document.getElementById('div');

    const throttle = (fn, wait) => {
        let pre = 0, context, args, timer;

        const run = () => {
            pre = +new Date();
            fn.apply(context, args);
            clearTimeout(timer);
            timer = null;
        }

        return function() {
            context = this;
            args = arguments;
            const now = +new Date();
            const remain = wait - (now - pre);
               if(Math.abs(remain) > wait || remain < 0) {
                   pre = +new Date();
                   fn.apply(context, args);
               } else if(!timer){
                   timer = setTimeout(run, wait);
               }
        }
    };

    const fn = throttle((e) => {
        console.log('move', e);
    }, 1000)

    div.addEventListener('mousemove', fn);
</script>
</html>
原文地址:https://www.cnblogs.com/innooo/p/10419953.html