给onScroll减减压
2015-05-29 18:06
351 查看
现在很多功能都需要监听onscroll事件完成的,然而onscroll触发得很频繁也是众所周知。
测试一下(请先让浏览器出现滚动条)
弊端
onScroll触发多少次,就会执行多少次clearTimeout、setTimeout,
一直滑动滑轮的时候,不会触发处理函数,因为onScroll一直在clearTimeout。
弊端
setInterval一直占用内存。
而setInterval的方式,setInterval一直占用内存,但大多数的情况下,它只做判断,就是判断change是否为true。
onscroll真的只做一件事,就是设置change变量为true,压力少了很多。
由此可见,setInterval 优于 setTimeout。
但我们总不能一个处理,添加一个onScroll、一个setInterval呢,所以写成模块。
模块代码
测试例子
测试一下(请先让浏览器出现滚动条)
var no = 0; /** * 统计触发次数 */ function statistical() { console.log( ++no ); } window.addEventListener('scroll', function() { statistical(); });
减压方式
1.setTimeout、clearTimeout
var no = 0, timeout; /** * 统计触发次数 */ function statistical() { console.log( ++no ); } window.addEventListener('scroll',function() { if ( timeout ) { clearTimeout( timeout ); } timeout = setTimeout(function() { statistical(); timeout = null; },300); });
弊端
onScroll触发多少次,就会执行多少次clearTimeout、setTimeout,
一直滑动滑轮的时候,不会触发处理函数,因为onScroll一直在clearTimeout。
2.setInterval
var change = false, no = 0; /** * 统计触发次数 */ function statistical() { console.log( ++no ); } /** * 间隔一定时间判断滚动坐标是否变化,变化则执行处理 */ setInterval(function() { if ( change ) { change = false; statistical(); } },300); /** * 监听onScroll事件,告诉setInterval,滚动坐标已经发生改变 */ window.addEventListener('scroll',function() { change = true; });
弊端
setInterval一直占用内存。
总结
setTimeout的方式clearTimeout、setTimeout太频繁,压力还是相当大;而setInterval的方式,setInterval一直占用内存,但大多数的情况下,它只做判断,就是判断change是否为true。
onscroll真的只做一件事,就是设置change变量为true,压力少了很多。
由此可见,setInterval 优于 setTimeout。
但我们总不能一个处理,添加一个onScroll、一个setInterval呢,所以写成模块。
模块代码
!(function( obj ) { //异步执行,有更好的方法,详见http://blog.csdn.net/zakkye/article/details/45890829 var asynFire = asynFire || function(handle) { setTimeout.call( window, handle ) }; //eventId前缀,是个随机字符串,避免一个页面存在两个 scrollListener 的时候,eventId相同 var idPf = Math.random().toString(36).substr(2).substr(0,4) + '_', //累加Id guid = 1, //window 当前的scrollLeft nX = 0, //window 当前的scrollTop nY = 0, //setInterval Id interval = 0, //scrollListener 监听事件所用id eventId = '.scrollListener', //是否已初始化 inited = false, //setInterval 延迟时间 lazy = 300, //所有回调缓存对象 callbacks = {}, //滚动坐标是否已改变 change = false; /** * 初始化,对基本属性赋值及添加监听 */ function init() { //已经初始化就不操作 if ( inited ) return; addEvent(); addInterval(); inited = true; } /** * 添加scroll事件监听 */ function addEvent() { $(window).on('scroll' + eventId,function(e){ change = true; }); } /** * 删除scroll事件监听 */ function removeEvent () { $(window).off(eventId); } /** * 添加循环监听 */ function addInterval () { interval = setInterval(function(){ determine(); }, lazy); } /** * 删除循环监听 */ function removeInterval () { clearInterval( interval ); interval = null; } /** * 判断当时是否应该执行回调 */ function determine() { var $window, _oX, _oY, _nX, _nY; if ( change ) { change = false; $window = $(window); _oX = nX; _oY = nY; _nX = $window.scrollLeft(); _nY = $window.scrollTop(); scrollListener.fire( _nX, _nY , _nX > _oX, _nY > _oY ); nX = _nX; nY = _nY; } } /** * 滚动监听功能(减少onscroll处理压力) * @type {Object} */ var scrollListener = { /** * add 添加处理 * @param {Function} callback * @return {boolean || number} 添加成功返回对应id,否则返回false */ add : function( callback ) { var id, $window; if ( typeof callback === 'function' ) { $window = $( window ); if ( !inited ) { init(); } id = idPf + ( guid++ ); callbacks[id] = callback; //由于会先执行一次,所以必须先返回eventId,再执行,所以用了异步,而且事件监听本来也属于异步 //也存在一些函数,判断页面已经滚动到相应区域,执行一次处理后,就要scrollListener.remove了,所以必须异步 asynFire(function() { callback({ x : $window.scrollLeft(), y : $window.scrollTop(), right : true, down : true }) }); return id; } return false; }, /** * 删除处理 * @param {number} id 添加回调时返回的id * @return {boolean} 是否删除成功 */ remove : function( id ) { if (id && callbacks[id]) { delete callbacks[id]; return true; } return false; }, /** * 执行所有回调 * @param {number} x 滚动条x坐标 * @param {number} y 滚动条y坐标 * @param {boolean} right 是否为向右滚动 * @param {boolean} down 是否为向下滚动 * @return {scrollListener} */ fire : function( x, y, right, down ) { var i, data = { x : typeof x === 'number' ? x : $(window).scrollLeft(), y : typeof y === 'number' ? y : $(window).scrollTop(), right : typeof right === 'boolean' ? right : true, down : typeof down === 'boolean' ? down : true }; for (i in callbacks) { callbacks[i]( data ); } return this; }, /** * 设置监听延迟时间 * @param {number} time 时间戳 * @return {scrollListener} */ setLazy : function( time ) { if ( typeof time === 'number' ) { //如果已经初始化,则马上修改监听时间 lazy = time; if ( inited ) { removeInterval(); addInterval(); } } return this; }, /** * 销毁 * @return {scrollListener} */ destroy : function () { removeEvent() removeInterval(); inited = false; callbacks = {}; return this; } } obj.scrollListener = scrollListener; })( window );
测试例子
var id1 = scrollListener.add(function() { console.log('scroll1'); }); var id2 = scrollListener.add(function() { console.log('scroll2'); }); scrollListener.remove( id2 );
相关文章推荐
- div scroll始终在最底部的实现代码
- jQuery插件scroll实现无缝滚动效果
- Class Of Marquee Scroll通用不间断滚动JS封装类第1/2页
- Javascript模拟scroll滚动效果脚本第1/2页
- 页面滚动条滚动后返回事件----JS
- HTML精确定位:scrollLeft,scrollWidth,clientWidth,offsetWidth之完全详解
- Christian louboutin voice
- 关于JSP数据库连接的问题?
- How to Perfectly Uninstall Ask Toolbar
- iPhone开发之UIScrollView滚动问题
- 游标操作
- runescape money 5 Basic FFXI Gil Tips
- StrokeIt 按键列表
- Scrolling Large Data Sets in Flex Charts
- Windows 8: Tips and Tricks for mouse/keyboard users
- Asp.net DataGrid control with Fixed Header and Scrollbar
- 开端...
- C#命名规则和开发习惯(引用于天上的星星亮晶晶(zj492)的blog)
- 在JSP中访问数据库大全
- BS开发中常用的javascript技术