Home  >  Q&A  >  body text

JavaScript throttle 的疑问

<!DOCTYPE html>
<html>
<head>
    <title>Throttle</title>
</head>
<body>
    <script type="text/javascript">
        var count = 0;
        var resizehandler = function () {
            console.log(new Date().getTime());
            console.log(count++);
        }

        var throttle = function (method, context){
            clearTimeout(method.tId);
            method.tId = setTimeout(function(){
                method.call(context);
            }, 100);
        }

        window.onresize = function(){
            throttle(resizehandler, window);
        };


    </script>
</body>
</html>

我的疑问是为什么我在一直拖的情况下,一直没有打印出第一次出现的结果。

因为按照我的理解,执行到setTimeout()以后,应该在0.1秒后打印内容,但是一直拖就没结果,想知道为什么。

PHP中文网PHP中文网2749 days ago213

reply all(2)I'll reply

  • ringa_lee

    ringa_lee2017-04-10 15:06:20

    因为你一直在 resize. 此时你原来设定的事件处理器被 clearTimeout() 掉了,在连续的 resize 事件 (两次之间的间隔 < 100ms) 只有最后一次绑定的事件处理程序被调用。

    设想 window 发生一次 resize 事件时,你在事件处理器中使用 setTimeout() 添加了一个将于 100ms 后调用的 resizeHandler() 函数,并且把这个 timeout 的 ID 存储在 resizeHandler.tId 里面。但是在 20ms 后, window 又发生了一次 resize 事件,此时首先 clearTimeout() 被调用,之前添加的 resizeHandler() 函数将不会得到执行。

    所以对于连续发生的 resize 事件,我们可以得出什么结论呢? —只有当一次 resize 与下一次之间的时间间隔大于 100ms 时,这个 resizeHandler() 才会得到调用。这也就是你说的:

    我的疑问是为什么我在一直拖的情况下,一直没有打印出第一次出现的结果。

    今天早上在 CNBlogs 看到一个 throttle 实现 (http://www.cnblogs.com/dolphinX/p/3403821.html) 可以解决你所碰到的问题:

    function throttle(method, delay, duration) {
        var timer = null, begin = new Date();
        return function () {
            var context = this,
                args = arguments,
                current = new Date();
            clearTimeout(timer);
            if (current - begin >= duration) {
                method.apply(context, args);
                begin = current;
            } else {
                timer = setTimeout(function () {
                    method.apply(context, args);
                }, delay);
            }
        };
    }
    
    

    (个人理解) 则在两次事件间隔时间大于 delay 时,或者事件发生时距离上一次重置 begin 不低于 duration, 则 method 均能得到调用,其中,在后一种情况下,会把 begin 重置为事件发生的时刻。

    调用该函数:

    window.onresize = throttle(resizehandler, 100, 200);
    

    除此之外,我也用 jQuery 写了一个 至多每隔一段时间 调用的 throttle 扩展:

    (function ($) {
        if (!$) { return; }
        $.fn.throttle = function (eventName, f, dur) {
            /// <param name="eventName" type="String"/>
            /// <param name="f" type="Function"/>
            /// <param name="dur" type="Number"/>
            dur = dur || 400;
            var that = this, g = function () {
                setTimeout(function () {
                    that.each(f).one(eventName, g);
                }, dur);
            };
            that.one(eventName, g);
            return that;
        }
    })(window.jQuery);
    

    (关于 jQuery.fn.one, 详见 http://api.jquery.com/one/)

    调用:

    $(window).throttle("resize", resizeHandler, 100);
    

    这样就可以在连续 resize 的情况下每 0.1s 打印输出内容,而在不 resize 的情况下则不输出任何内容。

    以上。
    (有用请支持/采纳。)

    reply
    0
  • PHP中文网

    PHP中文网2017-04-10 15:06:20

    一直拖就一直 clearTimeout 了,所以不打印了

    reply
    0
  • Cancelreply