javascript 发生单击事件时,重置承诺中的setTimeout()

mi7gmzs6  于 2023-01-11  发布在  Java
关注(0)|答案(2)|浏览(119)

以下是我所面临的问题的一个非常简单的再现:

window.onload=function(){
    touchme = document.getElementById('click');
    function mains(){
        touchme.innerHTML = "clicked " + Math.random().toString();
    }
    function process() {
        touchme.dataset.clicked = "false";
        mains();
        touchme.addEventListener("click", () => {
            touchme.dataset.clicked = "true";
        }, {once : true});

        let clickPromise = new Promise((resolve, reject) => {
            var timer = setTimeout(() => {
                if(touchme.dataset.clicked == "true"){
                    resolve();
                }
                else{
                    reject();
                }
            }, 1500);
        });
        
        clickPromise.then(() => { 
            process();
        });

        clickPromise.catch(() => {
            alert("game over");
        });
    }

    process();
}

这段HTML代码已经被使用了
我基本上想要的是:

  • 如果单击该按钮,mains()将立即运行
  • 如果我不这样做,setTimeout()将等待1.5秒。在此时间内,如果我单击,setTimeout()将重置,mains()将执行
  • 如果我仍然没有点击,alert("game over")就会被执行。“self回调循环”中断

但是,mains()函数并不是在我每次单击时立即运行,而是等待超时,导致每次单击后延迟1.5秒。
当然,解决方案是使用clearTimeout(),但是,我似乎不知道在哪里使用它。将它添加到事件侦听器的函数参数中会导致超时独立于单击事件运行,并使它在1.5s后拒绝承诺,尽管我单击了按钮。我还尝试在事件侦听器函数中调用函数本身。这是不起作用的,在if(touchme.dataset.clicked == "true")中,在setTimeout()之外,在promise中添加它是不起作用的,因为我的初始值是false,所以它只检查初始状态。

zkure5ic

zkure5ic1#

你真的不需要为此使用promise,只需要一个简单的处理函数就可以使清除和重置超时变得容易得多:

let lost = false;

function timeoutHandler() {
  alert("game over");
  lost = true;
}

let timeout = setTimeout(timeoutHandler, 1500);
document.getElementById('click').addEventListener('click', () => {
  if (lost) return;
  clearTimeout(timeout);
  timeout = setTimeout(timeoutHandler, 1500);
});
<button id="click">Click</button>
nkhmeac6

nkhmeac62#

这为Promise.race提供了一个很好的用例:

async function main() {
  while (await game()) {}
}

async function game() {
  let clickPromise = new Promise(res =>
    document.querySelector('button').onclick = () => res(true))

  let timerPromise = new Promise(res =>
    setTimeout(() => res(false), 1500))

  let ok = await Promise.race([clickPromise, timerPromise])

  document.querySelector('button').textContent = ok 
    ? 'keep clicking ' + Math.random() 
    : 'game over'

  return ok
}

window.onload = main
<button>click</button>

相关问题