首页 > 代码库 > “如何稀释scroll事件”的思考(不小心写了个异步do...while)
“如何稀释scroll事件”的思考(不小心写了个异步do...while)
看了下园友的一帖子:http://www.cnblogs.com/xzhang/p/4145697.html#commentform
本来以为是很简单的问题,但仔细想想还挺有意思的。简单的说就是增加事件触发的间隔时间。
比如在浏览器的事件是1毫秒调用一次,转换成100毫秒调用一次。
看了下原贴的两方法,觉得可以乐观锁的方法再写个,虽然最后对比结果和typeahead差不多。但过程还是挺有意思的,分享下思路
首先,浏览器事件间隔是没法改变的。所以我们只能改变回调函数的执行间隔。
乐观锁机制的流程是:
do { var _oldVal = _nowVal//记录基准值 //执行任务 } while (_oldVal != _nowVal)//比较 检查_nowVlau是否在执行任务的时候发生变化
根据这个结构,基本的设计思路就是:
触发事件时启动一个“任务线程”,执行完指定的任务后,隔一段时间去检查没有没有发生后续事件(通过_oldVal与_nowVal判断),如果有重新执行任务,没有结束线程。
但有一个问题,“任务线程”同一时间只能执行一个,所以在触发事件的时候要做下判断。修改后的程序
var _taskRun = false, _nowVal = 0, _oldVal = 0; function eventFun() { if (_taskRun) { _nowVal++; } else { _taskRun = true; do { var _oldVal = _nowVal//记录基准值 //执行任务 } while (_oldVal != _nowVal)//比较 检查_nowVlau是否在执行任务的时候发生变化 _taskRun = false;//执行结束重置状态变量 _nowVal = 0; } }
一切很顺利,但是要有间隔啊!js里可没有Thread.sleep,但有setTimeout,所以可以用setTimeout模拟sleep
SO,Think.....了一会,不小心写了个异步do...while
var _taskRun = false, _nowVal = 0, _oldVal = 0, _time = 100; var _do = function (waitTime, funTsk) {//模拟do{}while(true); var _endInner, _whileInner; _whileInner = function (funcondition) { _endInner = function (funEnd) { var _funWhile = function () { if (funcondition()) { _endInner(funEnd); } else { funEnd(); } }; var _runInner = function () { funTsk(); setTimeout(_funWhile, waitTime);//延迟一段时间做判断 }; _runInner(); }; return { "end": _endInner }; }; return { "while": _whileInner }; }; return function () { if (_taskRun) { _nowVal++; } else { _taskRun = true; _do( 100,//间隔时间 function () { _oldVal = _nowVal//记录基准值 console.log(_oldVal); } ) .while( function () { return _oldVal != _nowVal } ) .end( function () { _taskRun = false;//执行结束重置状态变量 _nowVal = 0; } ); } }
现在,基本OK了,但做了下测试,发觉间隔时间没有typeahead的准,怎么加事?
研究了下他的代码。发现高手的思路就不不一样。原来他是用当前时间去计算setTimeout的调用间隔的。SO出来的结果更加准确。
比如,设置间隔100秒,一个事件在距上个事件50秒的时候发生,为了保证每次100秒的间隔,这个事件的setTimeOut时间就应该设置成50秒而不是100秒
根据这个思路再修改了下代码,给出完整版:
var _asynFun = function (func, wait) { var context, args, result, _taskRun = false, _nowVal = 0, _oldVal = 0; var _do = function (waitTime, funTsk) {//模拟do{}while(true); var _endInner, _whileInner; _whileInner = function (funcondition) { _endInner = function (funEnd) { var _funWhile = function () { if (funcondition()) { _endInner(funEnd); } else { funEnd(); } }; var _runInner = function () { var _previous = new Date(); result = funTsk.apply(context, args); var _remaining = waitTime - ((new Date()) - _previous); setTimeout(_funWhile, _remaining);//延迟一段时间做判断 }; _runInner(); }; return { "end": _endInner }; }; return { "while": _whileInner }; }; return function () { context = this; args = arguments; if (_taskRun) { _nowVal++; } else { _taskRun = true; _do( wait,//间隔时间 function () { _oldVal = _nowVal//记录基准值 func(); } ) .while( function () { return _oldVal != _nowVal } ) .end( function () { _taskRun = false;//执行结束重置状态变量 _nowVal = 0; } ); } return result; } }
本文版权归作者和博客园共有,未经作者本人同意禁止任何形式的转载,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
最后再贴出测试代码:
“如何稀释scroll事件”的思考(不小心写了个异步do...while)