clearTimeout 不适用于 mouseup 事件

clearTimeout not working on mouseup event

为什么在此设置中没有清除超时?我怎样才能使 up() 停止 运行 的延迟操作?

var active = false;
var delay;

window.addEventListener("mousedown", down, false);
window.addEventListener("mouseup", up, false);
window.addEventListener("mousemove", move, false);

function down(e) {
    active = true;
    console.log("down")
    window.scrollTo(0,document.body.scrollHeight);
}

function up(e) {
    active = false;
    clearTimeout(delay); //expecting this to clear delay
    console.log("up")
    window.scrollTo(0,document.body.scrollHeight);
}

function move(e) {
    if (active) {
        delay = setTimeout(function() {
            console.log("move")
            window.scrollTo(0,document.body.scrollHeight);
        }, 50);
    }
}

期望在 mouseup 上清除延迟,但它仍在执行。

你总是在每一个动作上暂停。它不会取代最后一个...

你的代码基本上就是这样

delay = setTimeout(function() { } <-- will run
delay = setTimeout(function() { } <-- will run
delay = setTimeout(function() { } <-- will run
delay = setTimeout(function() { } <-- will run
delay = setTimeout(function() { } <-- will run
delay = setTimeout(function() { } <-- will run
delay = setTimeout(function() { } <-- cancels this one
window.clearTimeout(delay)

所以你需要在创建新的之前删除它

if (active) {
    if (delay) window.clearTimeout(delay)
    delay = setTimeout(function() {
        console.log("move")
        window.scrollTo(0,document.body.scrollHeight);
    }, 50);
}

如果您需要多次触发,您需要查看节流脚本。

答案:

您的代码中有几处需要调整:

  • 不要用新的 Timeout 计时器不断重新分配 delay,只需使用 Interval.
  • 只有当状态处于活动状态时才应设置计时器 AND 延迟尚不存在。 这会停止现有的多个计时器

JavaScript中的定时器有几点需要调整和理解:

  • 当您设置定时器时,容纳定时器的变量被设置为 return 一个整数。这是当前范围内定时器的 ID。
  • 当您清除计时器时,变量不会重置为 undefined - 它保持不变 Integer/ID。这是因为您没有清除 变量,范围正在停止与变量所在 ID 匹配的 Timer
  • 由于上述原因,您必须明确地将容纳计时器的变量设置为 undefined(或其他一些 falsy 值)after 清除它存在检查工作。

var active = false;
var delay;

window.addEventListener("mousedown", down, false);
window.addEventListener("mouseup", up, false);
window.addEventListener("mousemove", move, false);

function down(e) {
    active = true;
    console.log("down")
    window.scrollTo(0,document.body.scrollHeight);
}

function up(e) {
    active = false;
    clearTimeout(delay); //expecting this to clear delay
    delay = undefined;
    console.log("up")
    window.scrollTo(0,document.body.scrollHeight);
}

function move(e) {
    if (active) {
      if(!delay) {
        delay = setInterval(function() {
            console.log("move")
            window.scrollTo(0,document.body.scrollHeight);
        }, 50);
      }
    }
  else { //fallback in case of Browser Queuing issues
   if(delay) { 
     clearTimeout(delay);
     delay = undefined;
   }
  }
}

已编辑

由于对问题的评论,我在 mousemove 中添加了一个回退,如果状态为非活动状态,它将删除计时器,但 delay 仍被定义。我不认为你在技术上应该需要这个,但在实践中浏览器事件队列和定时器偶尔不会像预期的那样相处。

因此,我从回复中了解到,每次执行 move() 时,setTimeout 都会生成一个新的独立计时器。我的理解是每个新计时器都会覆盖前一个计时器,但由于情况并非如此,我不得不考虑其他事情。

我并没有真正解释我实际需要通过延迟实现什么,所以让我澄清一下。如果某个动作在 x 时间内没有执行,我想为该动作创建一个超时。在操作上使用 setTimeout 它自己会产生一个问题,即即使在 mouseup 事件之后,该操作仍可能有多个排队执行等待发生。

因此,我对一个新变量使用了 setTimeout,该变量充当操作的锁定。结果是下面的代码:

var active = false;
var actionTimeout = false;
var actionTimeStamp;
var actionLock = false;

window.addEventListener("mousedown", down, false);
window.addEventListener("mouseup", up, false);
window.addEventListener("mousemove", move, false);

function down(e) {
    active = true;
    console.log("down")
    window.scrollTo(0,document.body.scrollHeight);
}

function up(e) {
    active = false;
    console.log("up")
    window.scrollTo(0,document.body.scrollHeight);
}

function move(e) {
    if (active) {
        if ((Date.now() - actionTimeStamp > 500) && (!actionTimeout)) { // get time elapsed and compare to threshold (500ms)
            actionTimeout = true; //this is for the if statement above to prevent multiple timeouts
            actionLock = false; // set the lock
            setTimeout(function() { // remove lock after 50ms
                actionTimeout = false;
                actionLock = true;
                actionTimeStamp = Date.now(); // timestamp here to make sure we don't lock again to soon. (helps if setTimeout is => than threshold.
            }, 50);
        }
        if (actionLock) { //do our action
            console.log("move")
            window.scrollTo(0,document.body.scrollHeight);
            actionTimeStamp = Date.now();  // timestamp last execution
        }
    }
}

感谢大家的评论和回答。非常感谢。