JS 节流阀

JS 节流阀

参考 https://github.com/hahnzhu/read-code-per-day/issues/5

节流阀

节流阀的基本原理
事件函数的执行都记下当前时间, 只有当前时间与上次执行时间有一定间隔的时候才会去执行真正的逻辑

    function throttleMe(cb){
        console.log('move');
        var start = +new Date();
        return function(){
            var now = new Date();
            if(now - start > 1000){
                start  = now;
                cb();
            }
        }
    }
    $(window).on('mousemove', throttleMe(function(){
        console.log('timer');
    }));

有的书上是这么实现的 这个并不好用

var resizeTimer = null;
$(window).on('mousemove', function (e) {
        console.log('move');
    /* 第一次访问,不存在 resizeTimer,跳过这里 */
    if (resizeTimer) {
        clearTimeout(resizeTimer);
    }
    /* 第一次访问,赋值给 resizeTimer,绑定的函数 400ms 后调用 */
    resizeTimer = setTimeout(function(){
        console.log("move timer" /*+ e.clientX + '-' + e.clientY*/ );
    }, 40);
});

发现实际中并不是40ms调用一次move timer
原因就在于timeout 它是等这个函数执行完之后间隔40ms 才有机会去执行下一个函数

    function throttle(func, wait) {
        var context, args, timeout, result;
        var previous = 0;
        var later = function() {
            previous = +new Date();
            timeout = null;
            result = func.apply(context, args);
        };
        return function() {
            var now = +new Date();
            var remaining = wait - (now - previous); //距离下次执行剩余时间
            console.log('remaining'+remaining + 'now'+ now);
            context = this;
            args = arguments;
            if (remaining <= 0) { //过了间隔时间段  开始执行
                clearTimeout(timeout);
                timeout = null;
                previous = now;
                console.log('<0<0<0');
                result = func.apply(context, args);
            } else if (!timeout) {
                console.log('set time out------------');
                timeout = setTimeout(later, remaining);
            }
            return result;
        };
    }

函数去抖

    function debounce(fn, threshhold, scope) {
        threshhold || (threshhold = 250);
        var last,
            deferTimer;
        return function() {
            console.log('move');// 这个函数是mousemove事件处理的函数
            var context = scope || this;

            var now = +new Date,
                args = arguments;
            if (last && now < last + threshhold) {
                // hold on to it
                clearTimeout(deferTimer);
                deferTimer = setTimeout(function() {
                    last = now;
                    fn.apply(context, args);
                }, threshhold);
            } else {
                last = now;
                fn.apply(context, args);
            }
        };
    }
    $('body').on('mousemove', function() {
        console.log('move');
    });
    $('body').on('mousemove', debounce(function(event) {
        console.log('tick');
    }, 1000));

每次mousemove都是在执行 debounce返回的一个函数
这个返回的函数用到了debounce中的一个变量last
奇怪! 这个last 又不是全局的变量 为什么这个函数每次执行都依赖上次last的结果? 因为这里是一个闭包

通过闭包 使局部变量变成全局变量

因为这个a后面一直被fun函数使用 所以这个变量不会被销毁 正是闭包特性

function closure(){
    var a = 1;
    return function(){
        return ++a;
    }
}
fun = closure();
console.log(fun());//2
console.log(fun());//3
console.log(fun());//4
posted @ 2015-08-10 10:20  cart55free99  阅读(2764)  评论(1编辑  收藏  举报