背景:我在segmentfault提了个问题如何稀释onscroll事件,问题如下:

面试时问到这个问题,是这样的:
    面试官问一个关于滚动到某个位置的时候出现一个顶部的导航栏,答完之后,她接着问一滚动onscroll就会执行很多很多次,如何稀释它?为了确定她说的是“稀释”,我让她重复了遍,我给出的解决方法是,用一个变量,在事件处理的时候让它自增,判断达到一定大小就执行一次实际的事件:

var i = 0;    // 累积变量
window.onscroll = function(){
i++;
if(i%500==0){
// 执行实际的事件
}
}
  • 她并不满意,问最后如何释放这个变量?
  • ……
  • 接着她说:“我要的是稀释onscroll的执行次数,而不是这个(我所指的实际的事件)的执行次数。”
  • 我很是不解,鼠标一滚动就触发这个事件,如何能减少它的执行次数,如何稀释它?难道动态绑定/解绑事件,如何操作?

    网上都没有找到相关类型的问题,这个问题算不算变态级的面试题?如果不是,请给出解决方案,先谢谢了。

第一个回答认为这是函数节流,顿时恍然大悟,纳为答案,这是我和该名词的初次接触,本以为就这样结束了,没想到接下来又吸引了一大波程序员的眼球。

基本地,指出使用 throttle 和 debounce 两种方式:

throttle(译:节流阀):就是函数节流的意思,控制函数调用的频度,固定时间间隔执行,即连续的调用中,不管频度如何,只间隔固定时间(或大于该时间,这时频度较低)执行一次,不是问题中的“稀释”。

debounce(译:防反跳?):就是去抖的意思,空闲控制,在一定空闲时间间隔内的调用不予实现,一个简单的实现如下:

 var timer = null;
document.addEventListener('mousemove', function () {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(function(){
console.log("mousemove");
}, 100);
}
);

主要应对高度频发的调用,100的意思不是100ms执行一次,而是当调用间隔时间不超过100ms,即鼠标移动速度过快的话,console.log()会一直不被执行,除非移动间隔时间大于100ms,用网友bumfod的话,「函数节流让一个函数只有在你不断触发后停下来歇会才开始执行,中间你操作得太快它直接无视你。」,不是问题中的“稀释”。

综上,诚然 throttle 和 debounce 都能很好地解决性能问题,二者稀释的是业务逻辑的执行次数,但都不是问题所要求的,这时我就觉得这个问题有点牵强了,因为不管怎样,不管有没有显性地定义 scroll 事件,浏览器都会触发 scroll 事件的,差别在于有没有 callback,有没有要执行的东西而已。

如果非要“减少scroll 的执行次数”,这里有一位和我不谋而合的网友代码,通过setTimeout,执行一次再延时重新绑定事件监听器,这种方法稀释的是回调的执行次数

 var cb = {
onscroll:function() {
console.log("scrolling");
window.removeEventListener("scroll", cb.onscroll, false); // 这里移除事件监听器
setTimeout(function() {
console.log("DONE");
window.addEventListener("scroll", cb.onscroll, false);
}, 200); // 200ms后重新绑定事件监听器
}
};
window.addEventListener("scroll", cb.onscroll, false);

还有同学引出了阻塞渲染、影响页面UI响应等的问题,

其他:

框架辅助 _debounce(underscore.js 里的 debounce 函数)

 /**
* [debounce description]
* @param {[type]} func [回调函数]
* @param {[type]} wait [等待时长]
* @param {[type]} immediate [是否立即执行]
* @return {[type]} [description]
*/
_.debounce = function(func, wait, immediate) {
var timeout, args, context, timestamp, result; var later = function() {
var last = _.now() - timestamp; //小于wait时间,继续延迟wait-last执行later,知道last >= wait才执行func
if (last < wait && last > 0) {
timeout = setTimeout(later, wait - last);
} else {
timeout = null;
if (!immediate) {
result = func.apply(context, args); if (!timeout) context = args = null;
}
}
}; return function() {
context = this;
args = arguments;
timestamp = _.now();
//是否立即执行
var callNow = immediate && !timeout; if (!timeout) timeout = setTimeout(later, wait); if (callNow) {
result = func.apply(context, args);
context = args = null;
} return result;
};
};

underscore.js 的 debounce

typeahead 的 throttle 实现源码:

 throttle: function(func, wait) {
var context, args, timeout, result, previous, later;
previous = 0;
later = function() {
previous = new Date();
timeout = null;
result = func.apply(context, args);
};
return function() {
var now = new Date(),
remaining = wait - (now - previous);
context = this;
args = arguments;
if (remaining <= 0) { //如果大于间隔时间(wait)
clearTimeout(timeout);
timeout = null;
previous = now;
result = func.apply(context, args);
} else if (!timeout) { //小于,延时调用later
timeout = setTimeout(later, remaining);
}
return result;
};
},

typeahead.js 的 throttle

如有纰漏,恳请指出,共同进步,谢谢^_^

“如何稀释scroll事件”引出的问题的更多相关文章

  1. “如何稀释scroll事件”的思考(不小心写了个异步do...while)

    看了下园友的一帖子:http://www.cnblogs.com/xzhang/p/4145697.html#commentform 本来以为是很简单的问题,但仔细想想还挺有意思的.简单的说就是增加事 ...

  2. 如何提高scroll事件的性能

    1. chrome devtool 是诊断页面滚动性能的有效工具 2. 提升滚动时性能,就是要达到fps高且稳. 3. 具体可以从以下方面着手 使用web worker分离无页面渲染无关的逻辑计算 触 ...

  3. jQuery scroll事件实现监控滚动条分页示例(转)

    这篇文章主要介绍了jQuery scroll事件实现监控滚动条分页简单示例,使用ajax加载,同时介绍了(document).height()与$(window).height()的区别,需要的朋友可 ...

  4. scroll事件实现监控滚动条并分页显示示例(zepto.js)

    scroll事件实现监控滚动条并分页显示示例(zepto.js  ) 需求:在APP落地页上的底部位置显示此前其他用户的购买记录,要求此div盒子只显示3条半,但一页有10条,div内的滑动条滑到一页 ...

  5. JQUERY 滚动 scroll事件老忘记 标记下

    制作笔记 这个scroll事件 老忘记.... 写的太垃圾了  希望有路过的大神指点的吧~ 这个貌似应该写个函数里 调用好些的吧~  写个类这样的 也方便扩展貌似  不过就是想想  ~ $(windo ...

  6. jQuery scroll事件

    scroll事件适用于window对象,但也可滚动iframe框架与CSS overflow属性设置为scroll的元素. $(document).ready(function () { //本人习惯 ...

  7. Android ScrollView 嵌套 ListView、 ListView 嵌套ScrollView Scroll事件冲突解决办法

    本人菜鸟一名,最近工作了,开始学习Android. 最近在做项目的时候,UX给了个design,大概就是下拉刷新的ListView中嵌套了ScrollView,而且还要在ScrollView中添加动画 ...

  8. 前端资讯周报 3.13 - 3.19: WebVR来了!以及如何优化scroll事件性能

    每周一我都会分享上一周我订阅的技术站点中,和解决问题的过程中阅读到的值得分享的文章.这是迫使我学习的一个动力 本周推荐 Minecraft in WebVR with HTML Using A-Fra ...

  9. 关于如何绑定Jquery 的scroll事件(兼容浏览器 Wookmark瀑布流插件)

    做一个随屏幕滚动的导航条时,发现一个问题: 火狐.谷歌.ie9正常,ie8.7.6页面滚动时,导航条没有反应. 代码如下: $(document).bind("scroll",fu ...

随机推荐

  1. 获取设备、APP的一些信息

    获取设备的一些信息: UIDevice *device = [UIDevice currentDevice]; @property(nonatomic,readonly,strong) NSStrin ...

  2. hdu2304Electrical Outlets

    Problem Description Roy has just moved into a new apartment. Well, actually the apartment itself is ...

  3. 垃圾回收器 Dispose 和 Finalize 的互补作用

    假如我们程序有两个窗口 Form1.Form2; 当我们关闭一个窗口的时候,会发出一个 终止响应,并将该窗口对象送入终止队列,公共语言运行库的垃圾回收器跟踪着这个对象的生存期,此时就会调用此对象的基类 ...

  4. 2015.4.16-SQL-内连接与外连接

    1.内连接 如图: 关键字 inner join 2.外连接 分为左外连接 和右外连接,即如果是左外连接,即使左面没有值,也会显示为null, 右外连接也如此 关键字 left join ; righ ...

  5. media type 与 media query

    参考博客:http://www.qianduan.net/media-type-and-media-query.html media type(媒体类型)是css 2中的一个非常有用的属性,通过med ...

  6. 【ecos学习5】redboot 加载运行hello world

    背景: 从主机 192.168.2.14 IP,下载bin文件hello到ecos. redboot>load -v -h 192.168.2.14 hello Using default pr ...

  7. C语言的本质(25)——C标准库之内存管理

    程序中需要动态分配一块内存时怎么办呢?我们可以定义一个缓冲区数组,但是这种方法不够灵活,C89要求定义的数组是固定长度的,而程序往往在运行时才知道要动态分配多大的内存,例如: void foo(cha ...

  8. EasyUI选项卡tab页面处理示例

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...

  9. system函数遇到的问题 - 程序死掉

    system函数遇到的问题 解决方案见最下边 http://blog.csdn.net/yangzhenzhen/article/details/51505176 这几天调程序(嵌入式linux),发 ...

  10. Longest Substring Without Repeating Characters 最长不重复子串

    只遍历一次字符串即可求出最长不重复子串的长度. int lengthOfLongestSubstring(string s) { vector<,-); //记录字符上一次出现的位置,ASCII ...