引子:昨天面试时面试官问了如何实现一个固定导航栏,在我答完后面试官问我可能存在哪些问题,如何优化?
这个问题我答得不太好,但现在回想起来应该有两个问题:
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;
参考链接: