简体   繁体   English

JavaScript:在单击事件时中断 promise 中的 setTimeout()

[英]JavaScript: Interrupt a setTimeout() inside a promise, upon a click event

Here is a very simplified reproduction of the issue I am facing:这是我面临的问题的非常简化的再现:

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();
}

This bit of HTML has been used <body><button id="click">Click</button></body> HTML这一位已经被使用了<body><button id="click">Click</button></body>

What I basically want is:我基本上想要的是:

  • if I click the button, mains() will run immediately如果我点击按钮, mains()将立即运行
  • if I don't, setTimeout() will wait 1.5secs for me.如果我不这样做, setTimeout()会为我等待 1.5 秒。 Within this time if I click, setTimeout() resets and mains() gets executed在这段时间内,如果我单击, setTimeout()将重置并执行mains()
  • if I still don't click, alert("game over") is executed.如果我仍然不点击,则执行alert("game over") The "self callback loop" breaks “自我回调循环”中断

However, the mains() function isn't being run immediately whenever I am clicking, instead it is waiting for the timeout, causing a delay of 1.5s after every click.但是,每当我单击时, mains() function 不会立即运行,而是等待超时,导致每次单击后延迟 1.5 秒。

Naturally, the solution is to use clearTimeout() , however, I can't seem to wrap my head around where to use it.自然地,解决方案是使用clearTimeout() ,但是,我似乎不知道在哪里使用它。 Adding it inside the function argument of event listener causes the timeout to run independently of the click event and just makes it reject the promise 1.5s later, notwithstanding my button clicks.将它添加到事件侦听器的 function 参数中会导致超时独立于单击事件运行,并使其在 1.5 秒后拒绝 promise,尽管我单击了按钮。 I also tried calling the function itself inside the event listener function, which doesn't work.我还尝试在事件侦听器 function 中调用 function 本身,但这不起作用。 Adding it inside an if(touchme.dataset.clicked == "true") outside the setTimeout() and inside the promise wouldn't work, as my initial value is false , so it just checks the initial state.将它添加到if(touchme.dataset.clicked == "true")setTimeout()外和 promise 内是行不通的,因为我的初始值为false ,所以它只检查初始 state。

You really don't need to use promises for this, just a simple handler function will make it a lot easier to clear and reset the timeout:你真的不需要为此使用承诺,只需一个简单的处理程序 function 就可以更容易地清除和重置超时:

 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>

This makes a good use case for Promise.race :这为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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM