前端性能优化——节流

和防抖不同,节流操作是指在连续触发某一事件的情况下,每隔一段时间就触发一次事件,时间固定,具体的使用场景和防抖的类似,不过我一般使用防抖,可以节省请求。

第一种方案:利用时间戳,直接执行

实现思路:如果当前时间减去上一次触发事件大于间隔事件,触发函数,并将当前时间赋值为记录时间,否则就无事发生

操作:当鼠标滑过某个区域后,停止滑动后,3000ms,计数器加一

export const throttle = (fn, wait) => {
    var context = this;
    // 变量:记录上一次时间, 初始化为0,会立即执行
    var previous = 0;
    return (...args)=>{
        // 获取当前毫秒数
        var now = +new Date()
        // 如果当前时间减去上一次触发事件大于间隔事件,触发函数,并将当前时间赋值为记录时间
        if(now - previous > wait){
            fn.apply(context, args)
            previous = now
        }
    }
}
import React from 'react';
import { throttle } from '@/util/plugins'
import './index.scss';

class Throttle extends React.Component {

    constructor(props){
        super(props);
        this.state = {
            count: 0
        }
        this.onMouseMove = throttle(this.onMouseMove, 3000)
    }

    onMouseMove = (a) => {
        this.setState(prev => ({
            count: prev.count + 1
        }), ()=>{
            console.log(this.state.count)
        })
    }

    render() {
        return 
            
} } export default Throttle;

第二种方案:利用定时器,wait时间后执行

实现思路:判断定时器是否存在,若不存在,新建定时器,wait时间后执行,执行后置定时器为null,若存在,无事发生

操作和页面同第一种方案

export const throttle = (fn, wait) => {
    var context = this;
    var timeout = null;
    return (...args) => {
        if(!timeout){
            timeout = setTimeout(()=>{
                timeout = null
                fn.apply(context, args)
            }, wait)
        }
    }
}

第三种方案:前两种方案结合,在开始时执行,结尾也执行

大体实现思路:计算剩余触发时间,若剩余触发时间<0,则立刻触发事件,否则的情况,如果没有定时器,则新建定时器,执行后置定时器为null,具体细节见函数

操作和页面同第一种方案

export const throttle = (fn, wait) => {
    var timeout = null, context = this;
    var previous = 0;

    var throttled = (...args) => {
        var now = +new Date();
        // 下次触发fn的剩余时间
        var remaining = wait - (now - previous);
        // 如果没有剩余的时间了, remain>wait,用户在执行期间,回调时间,几乎不可能出现
        if(remaining <= 0 || remaining > wait){
            // 若有定时器,清除
            if(timeout){
                clearTimeout(timeout)
                timeout = null
            }
 
            previous = now
            fn.apply(context, args)
        }else if(!timeout){
            timeout = setTimeout(()=>{
                previous =  now;
                timeout = null;
                fn.apply(context, args)
            }, remaining);
        }
    }

    return throttled
}

第四种方案:基于方案三,提供option,

实现效果:可以选择使用方案一({trailing: false})、方案二({leading: false})、方案三(三者互斥),补充解除节流属性cancel

export const throttle = (fn, wait, options) => {
    var timeout = null, context = this;
    var previous = 0;
    if(!options) options = {};

    var throttled = (...args) => {
        var now = +new Date();
        // 不需要一开始执行,则进入timeout
        if(!previous && options.leading === false) previous = now
        // 下次触发fn的剩余时间
        var remaining = wait - (now - previous);
        // 如果没有剩余的时间了, remain>wait,用户在执行期间,回调时间,几乎不可能出现
        if(remaining <= 0 || remaining > wait){
            
            if(timeout){
                clearTimeout(timeout)
                timeout = null
            }
            
            previous = now
            fn.apply(context, args)
            if (!timeout) context = null;
        }else if(!timeout && options.trailing !== false){
            // 若不需要结尾执行,则置trailing为false
            timeout = setTimeout(()=>{
                previous = options.leading === false ? 0 : +new Date();
                timeout = null;
                fn.apply(context, args)
                if (!timeout) context = null;
            }, remaining);
        }
    }

    throttled.cancel = () => {
        clearTimeout(timeout);
        previous = 0;
        timeout = null;
    }

    return throttled
}
import React from 'react';
import { throttle } from '@/util/plugins'
import './index.scss';

class Throttle extends React.Component {

    constructor(props){
        super(props);
        this.state = {
            count: 0
        }
        this.onMouseMove = throttle(this.onMouseMove, 3000, {leading: false})
        this.clickBtn = throttle(this.clickBtn, 10000)
    }

    onMouseMove = (a) => {
        this.setState(prev => ({
            count: prev.count + 1
        }), ()=>{
            console.log(this.state.count)
        })
    }

    clickBtn = () => {
        console.log('click')
    }
    render() {
        return 
            
} } export default Throttle;

最后

思路比代码重要
附:前端性能优化——防抖

你可能感兴趣的:(前端性能优化——节流)