首页 > 网站 > WEB开发 > 正文

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

2024-04-27 14:15:47
字体:
来源:转载
供稿:网友

“如何稀释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 };        };        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 [是否
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表