您的位置:首页 > Web前端 > JavaScript

JavaScript 频繁发射事件处理的优化 --- 函数节流/事件稀释

2014-11-15 08:42 609 查看
引子:昨天面试时面试官问了如何实现一个固定导航栏,在我答完后面试官问我可能存在哪些问题,如何优化?

这个问题我答得不太好,但现在回想起来应该有两个问题:

1. 把 fixbar元素 position:fixed 之后,它将脱离文档流,后面的元素将会跟上,这可能会形成一个闪烁,解决方法是跟随的元素设置 margin-top 为 fixbar 元素的高度,或者替换上一个等高的元素,这点面试时候没有描述出来。

2. 就是这篇博文主要内容 %26rdquo;函数节流%26ldquo;,英文名 throttle 函数,在一些库,如underscore中有其实现,

主要思想是:对于非常频烦发射的事件,可以设置一定时间的%26rdquo;缓冲%26ldquo;,在这一定的时间内只执行最后一次时间的响应函数。

例如对于 窗口的滚动条拖动,onscroll时间是非常频繁发射的,如果每次发射都执行事件处理函数,那么将会增加浏览器负担,这时如果200ms(只是举例)执行一次,那么性能上将有所改善,效果上也能接受,当然实际应用需要二者找到一个平衡。

%26nbsp;

JQuery作者 John Resig 在2011年的一篇博文中提出了这个问题的最佳实践方法,请点击原文查看。代码如下:

var outerPane = $details.find(".details-pane-outer"),
didScroll = false;

$(window).scroll(function() {
didScroll = true;
});

setInterval(function() {
if ( didScroll ) {
didScroll = false;
// Check your page position and then
// Load in more results
}
}, 250);


%26nbsp;

通俗地大家把它称为 函数节流/事件稀释, 在 underscore 中,也有这个实现:

throttle
_.throttle(function, wait, [options])
%26nbsp;

Creates and returns a new, throttled version of the passed function, that, when invoked repeatedly, will only actually call the original function at most once per every%26nbsp;waitmilliseconds. Useful for
rate-limiting events that occur faster than you can keep up with.
By default,%26nbsp;throttle%26nbsp;will execute the function as soon as you call it for the first time, and, if you call it again any number of times during the%26nbsp;wait%26nbsp;period,
as soon as that period is over. If you'd like to disable the leading-edge call, pass%26nbsp;{leading: false}, and if you'd like to disable the execution on the trailing-edge, pass%26nbsp;
{trailing: false}.

var throttled = _.throttle(updatePosition, 100);
$(window).scroll(throttled);


以下是具体的实现代码:

_.throttle = function(func, wait, options) {
var context, args, result;
var timeout = null;
var previous = 0;
if (!options) options = {};
var later = function() {
previous = options.leading === false ? 0 : _.now();
timeout = null;
result = func.apply(context, args);
if (!timeout) context = args = null;
};
return function() {
var now = _.now();
if (!previous %26amp;%26amp; options.leading === false) previous = now;
var remaining = wait - (now - previous);
context = this;
args = arguments;
if (remaining %26lt;= 0 || remaining %26gt; wait) {
clearTimeout(timeout);
timeout = null;
previous = now;
result = func.apply(context, args);
if (!timeout) context = args = null;
} else if (!timeout %26amp;%26amp; options.trailing !== false) {
timeout = setTimeout(later, remaining);
}
return result;
};
};


%26nbsp;

参考链接:

Learning from Twitter

underscore.js
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: