Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/jquery/80.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Javascript中,如果函数已经在执行,则对该函数的执行进行排队,但取消之前排队的任何操作_Javascript_Jquery - Fatal编程技术网

在Javascript中,如果函数已经在执行,则对该函数的执行进行排队,但取消之前排队的任何操作

在Javascript中,如果函数已经在执行,则对该函数的执行进行排队,但取消之前排队的任何操作,javascript,jquery,Javascript,Jquery,我经常遇到以下情况,所以我想知道是否有一种内置的jQuery方法来解决这个问题 想象一下下面的代码: $(document).click(function() { paintCanvas(); }); 这段代码的问题是,如果用户连续快速单击屏幕50次,您将通过50次调用paintCanvas使浏览器过载 如果paintCanvas当前正在执行,并且创建了一个新请求,我们希望对新请求进行排队,以便它等待paintCanvas完成执行。但是,同时,我们可以删除任何先前排队的paintCanv

我经常遇到以下情况,所以我想知道是否有一种内置的jQuery方法来解决这个问题

想象一下下面的代码:

$(document).click(function() {
   paintCanvas();
});
这段代码的问题是,如果用户连续快速单击屏幕50次,您将通过50次调用paintCanvas使浏览器过载

如果paintCanvas当前正在执行,并且创建了一个新请求,我们希望对新请求进行排队,以便它等待paintCanvas完成执行。但是,同时,我们可以删除任何先前排队的paintCanvas调用,因为我们只关心鼠标的最终状态,而不关心所有中间状态

下面是一些解决问题的代码:

var _isExecuting, _isQueued;

function paintCanvas() {
    if (_isExecuting) {
        if (!_isQueued) {
            _isQueued = true;
            setTimeout(function() {
                _isQueued = false;
                paintCanvas();
            }, 150);
        }
        return;
    }

    _isExecuting = true;

    // ... code goes here

    _isExecuting = false;
};

基本上实现了这一功能,但仅在AJAX方面实现。当然,这是一个非常常见的问题,可以用更通用的方法解决吗?

您不必用
mousemove
解决这个问题,因为系统已经为您解决了这个问题。当执行
paintCanvas
时,即使鼠标剧烈移动,也不会生成数百个mousemove事件。相反,下一个事件将是鼠标的当前位置,而不是所有中间鼠标事件的队列

看看这个JSFIDLE:

尽可能快地在主体(右下窗格)中晃动鼠标。然后将鼠标移出窗格,注意计数立即停止-不再有鼠标事件。它永远不会堆积鼠标事件。每当系统为下一个鼠标事件做好准备时,它都会获取鼠标的最新位置。单个鼠标移动不会排队-它们不会累积。您还可以在鼠标事件列表中看到,许多中间鼠标事件不存在(例如,许多坐标丢失),即使鼠标经过更多位置。这是因为当鼠标处于该位置时,系统尚未准备好创建鼠标事件,因此跳过了该位置


此外,因为javascript是单线程的,所以当您当前正在处理一个鼠标事件时,您将永远不会得到一个新的鼠标事件。系统将不会生成一个新的,直到你完成处理你已经是一个。因此,您永远不会在代码中看到javascript中的
执行
true
。你根本不需要那张支票。而且,由于您不需要该检查,而且它永远不会为真,因此您的任何排队代码都不会执行。您可以在这个JSFIDLE中看到,您永远无法捕获重新输入的mousemove事件:。无论鼠标摆动的速度有多快或摆动的幅度有多大,“不作为”标志永远不会被认为是真的。

听起来好像你想要节流/去盎司功能

据我所知,jQuery没有内置方法,但您可以使用以下任何一种方法:


虽然@rkw提供了一个链接,但我总是喜欢在这里显示代码。这里有一些简单的代码,可以满足您的需要。返回另一个函数的缓冲版本的函数。这将持续延迟,直到它停止接收给定
延迟的事件为止。如果您不想在最后一个事件后等待延迟,可以调整此设置。您需要做的就是跟踪第一次设置超时的时间,并将后续调用偏移到
setTimeout

这里有一个有效的例子


这很公平,但我并不关心mousemove,这只是一个示例来说明,而是任何您必须担心可能并行运行多个方法的情况。取而代之的是点击——如果用户点击50个不同的东西会发生什么。您不希望执行该方法50次,只希望在最后一次单击时执行它。我已经更新了示例以反映。我怀疑我的特定解决方案无论如何都不会起作用,因为您描述的原因。但问题仍然存在。我不同意,虽然浏览器确实会缓冲mousemove事件,但您可能希望缓冲时间比浏览器更长。但是你关于为什么不需要执行
(isExecuting
)的评论已经过时了。Ext-JS在设置处理程序时内置了相同的概念,你可以给它诸如Element.addListener(“单击”,这个,{buffer:150})之类的选项,在调用处理程序之前总是要等待200毫秒(除非它再次被调用,此时它将重新启动计数器)。我知道用户询问了jQuery,我只想提到其他框架构建了这个inI,例如,无法忍受jQuery:)我更喜欢OO代码而不是过程代码。这就是为什么我使用ExtJS,它完全基于OO。
function createBuffered(handler, delay) {
  var timeoutId = null;

  return function() {
     var me = this;
     if (timeoutId) {
        window.clearTimeout(timeoutId);
     }
     timeoutId = setTimeout(function() {
         handle.apply(me, arguments);
         timeoutId = null;
     }, delay);
  }
}