JavaScript中的函数节流

一. 背景

在一些场景下,函数有可能会被频繁地调用,而这些函数本身占用的内存或计算较大时,就可能造成大的性能问题。譬如以下场景:

window.onresize事件。window.onresize事件在浏览器窗口大小改变时被触发,而且浏览器每改变1px,该事件就被触发一次,触发的频率非常的高。如果在window.onresize事件中涉及到一些DOM节点相关的操作时,而DOM操作往往是非常耗内存的,这时浏览器有可能出现卡顿甚至崩溃的情况。
mousemove事件。如果给一个div元素上绑定了mousemove事件,当在该div上移动鼠标时,也会频频触发该mousemove事件函数。
window.onscroll事件。window.onscroll事件会在页面滚动时被触发,而且页面每滚动1px都会触发一次,触发的频率也非常高。
change事件。用户在input和textarea元素中每次改变value值都会触发change事件。当用户输入较快时,而change事件函数可能涉及到DOM操作等耗内存的操作时,则可能导致卡顿问题。
… …
而实际上,我们并不需要那么频繁地触发这些事件函数,只要能确保比较流畅的用户体验即可。

譬如拖拽浏览器窗口改变其大小时,window.onresize事件函数可能被触发了100次,而实际上我们只需要3、4次就可以达到比较流畅的用户体验。这就需要我们使用函数节流,按时间段来忽略一些事件请求,这个可以借助setTimeout函数来实现。

所以,函数节流需要做的是降低触发回调的频率。

二. 函数节流的原理

函数节流的原理是,将即将被执行的函数用setTimeout延迟一段时间后才执行。如果该次言辞执行还没有完成,则忽略接下来调用该函数的请求。

三. 函数节流的代码实现

*
 * 节流函数
 * @param {Function} fn 需要进行节流的函数
 * @param {Int} delay 函数执行的时间间隔。默认值为500
 */
var throttle = function(fn, delay) {
    var _self = fn, // 保存需要被延迟执行的函数引用
        timer = null, // 定时器
        firstTime = true; // 是否是第一次调用

    return function() {
        var args = arguments,
            _this = this,
            delay = delay || 500;

            // 如果是第一次调用,不需要延迟执行
            if(firstTime) {
                _self.apply(_this, args);
                firstTime = false;
                return;
            }

            if(timer) {
                return false;
            }

            // 延迟一段时间执行
            timer = setTimeout(function() {
                // 清除调原来的定时器
                clearTimeout(timer);
                timer = null;

                _self.apply(_this, args);
            }, delay);
    };
}
/* =============== 客户端调用 =============== */
window.onresize = throttle(function() {
    console.log("Window is resizeing.");
}, 200);

猜你喜欢

转载自blog.csdn.net/u011200023/article/details/73733765