Daily Notes

Just Some Notes

实现函数节流

/**
 * 函数节流
 * @param {function} func 需要节流的函数
 * @param {number} interval 函数的执行间隔(毫秒)
 * @param {object} options { leading: true, tailing: false }
 */
function throttle(func, interval, options) {
    let canRun = false,    // 是否可以执行函数
        lastInvokeTime = 0,    // 函数上一次被执行的时刻(时间戳)
        tid = null;    // 定时器id,设置间隔过后再次执行一次函数
    // leading和tailing不能同时为false
    const { leading = true, tailing = false } = options || {};
    const throttled = function throttled(...args) {
        let now = Date.now();
        if (!lastInvokeTime) {
            if (leading) {
                canRun = true;
            }
        } else {
            if (now - lastInvokeTime >= interval) {
                canRun = true;
            }
        }
        if (canRun) {
            if (tid) {
                clearTimeout(tid);
                tid = null;
            }
            canRun = false;
            lastInvokeTime = now;
            func.apply(this, args);
        } else if (!tid && tailing) {
            tid = setTimeout(function () {
                func.apply(this, args);
                lastInvokeTime = 0;
                tid = null;
            }, now - lastInvokeTime);
        }
    }

    /**
     * 取消最后一次的函数执行
     */
    throttled.cancel = function cancel() {
        lastInvokeTime = 0;
        if (tid) {
            clearTimeout(tid);
            tid = null;
        }
    }

    return throttled;
}

// test
let count = 0;
function increment() {
    count += 1;
    console.log((new Date().getSeconds()), count);
}

const incrementThrottled = throttle(increment, 3000);

while (count < 5) {
    incrementThrottled();
}
// test result
// 47 1
// 50 2
// 53 3
// 56 4
// 59 5