看了下园友的一帖子: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 }; }; function eventFun() { 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; } }
本文版权归作者和博客园共有,未经作者本人同意禁止任何形式的转载,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
最后再贴出测试代码:
<html><head> <title> “如何稀释scroll事件”测试 </title> <meta charset="utf-8"></head><body> <div style="margin:auto;width:600px;padding:20px"> <input id="waitTime" type="text" value="100" onchange="onscrollTest()" style="float:left" /> <select id="sel" onchange="onscrollTest()" style="float:left"> <option value="1">使用_lazyRun</option> <option value="2">使用debounce</option> <option value="3">使用throttle </option> <option value="4">使用_asynFun </option> </select> <div id="outDiv" style="float:left"></div> </div> <div style="width:auto;text-align:right;font-weight:bold;color:red;padding:10px;font-size:20px">滚动条----------------------------------------------></div> <div id="box" style="width:auto; height:200px;overflow-y:scroll;"> <div style="border-color:goldenrod;border: 2px solid #f60;height:6000px;width:auto;background-color:goldenrod"></div> </div></body></html><script type="text/javascript"> var _lazyRun = function (func, wait) { var _preIndex = 0, _nowIndex = 1, _timer, _fnCur, _context, _result; var _fn1 = function () { if (_preIndex < _nowIndex) { var _previous = new Date(); _fnCur = _fn2; clearTimeout(_timer); _preIndex = _nowIndex; _result = func.apply(_context, _args); var _remaining = wait - ((new Date()) - _previous); if (_remaining < 0) { _result = _fn1.apply(_context, _args); } else { _timer = setTimeout(_fn1, _remaining);//脱离线程 } } else { _fnCur = _fn1; _preIndex = 0, _nowIndex = 1; } return _result; }; var _fn2 = function () { _nowIndex++; return _result; }; _fnCur = _fn1; return function () { _context = this; _args = arguments; _result = _fnCur.apply(_context, _args); return _result; }; }; //**************************underscore.js 的 debounce /** * [debounce description] * @param {[type]} func [回调函数] * @param {[type]} wait [等待时长] * @param {[type]} immediate [是否
新闻热点
疑难解答