JavaScript 中的延迟函数调用合并

6

我不确定这个技术术语是什么。我有一个带有交互式图形的GUI。用户与GUI进行交互后,我需要执行一些CPU密集型操作。但是,由于用户输入非常频繁,因此我只想在没有用户输入1000毫秒后调用该函数。下面是我使用的模式:

scheduler = (function(){
    var timer;
    function exec(call, delay){
        clearTimeout(timer);
        timer = setTimeout(call, delay);
    };
    return exec;
})()

也就是说,如果对scheduler的三个调用紧接着进行,那么只会执行最后一个调用:

scheduler(function(){alert('foo')}, 1000);
scheduler(function(){alert('bar')}, 1000);
scheduler(function(){alert('zoo')}, 1000);

看起来它能工作,但感觉有点hacky,我有点担心Javascript setTimeout的任何注意事项,特别是作用域问题。这种模式是否可靠,可以在更大范围内使用?当我通过settimeout调用时,我传递给scheduler的内联函数是否能像往常一样查找其词法作用域中的所有对象?如果我有几个这样的scheduler实例,会发生干扰吗?是否有其他方法可以实现这一点?


你是想只运行最后一个操作还是想要所有的操作都运行? - Snuffleupagus
常见情况有常见解决方案。您需要使用“节流”或“去抖动”函数(http://benalman.com/projects/jquery-throttle-debounce-plugin/ 或 http://code.google.com/p/jquery-debounce/ 或类似的工具)。 - Victor
4个回答

1

我的做法:

http://jsfiddle.net/gunderson/4XXQ4/1/

    var severQueue = [];
    var delay;

    $("#inputSquare").mousemove(onMouseMove);

    function onMouseMove(){
        if (delay){
           clearTimeout(delay);
        }
        serverQueue.push("doSomething")
        delay = setTimeout(sendToServer, 1000);
    }

    function sendToServer(){
        console.log(serverQueue.length);
        delay = null;
        $("#inputSquare").addClass("activated");
        // do some ajax using serverQueue
        // we'll just simulate it with another timeout
        for (var i in serverQueue){
            serverQueue.pop();
        }
        onComplete = setTimeout(onAjaxComplete, 1000);
    }

    function onAjaxComplete(){
        $("#inputSquare").removeClass("activated");
    }

​

1

underscore.js中的debouncefunction函数恰好可以实现这一点:

debounce _.debounce(function, wait, [immediate])

创建并返回传递函数的新防抖版本,该函数将推迟其执行时间,直到自上次调用以来已经过去了wait毫秒。非常有用的实现行为仅在输入停止到达后才应发生的情况,例如:渲染Markdown评论的预览,在窗口停止调整大小后重新计算布局等。


1

虽然我倾向于同意他的目标受众可能不会。 :p - Snuffleupagus

1
从理论上讲,你的解决方案看起来是可行的。与你将回调函数传递给scheduler函数相关的作用域问题不存在;回调函数会像JavaScript中的任何其他函数一样封闭在它所创建的环境中。话虽如此,JavaScript中的作用域规则可能有些棘手,因此请确保您已经了解了它。
实际上,可能会存在一些特定于浏览器的与setTimeout相关的问题,这可能会使该解决方案无法正常工作。例如,某些浏览器执行setTimeout回调的频率可能会有所不同,以至于您将等待比预期更长的时间才能执行回调。所有setTimeout回调都将按顺序执行;它们永远不会并行执行。但是,您可以保证它们将按照什么顺序执行。
话虽如此,你的解决方案中可能存在的主要陷阱很可能与你注册的回调有关,而不是你注册它们的方式。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接