JavaScript 通用 Async/Await "debounce"

JavaScript generic Async/Await "debounce"

所以基本上我有一个异步事件回调,有时会很快触发。我想要做的是立即执行一些方法,但在执行代码的最后一位之前等待直到最后一次调用之后一段时间。

这里有一个例子:

let debounceTimeout
async function onEvent() {
    // do stuff here on every event

    const waitTime = 5000
    await new Promise(resolve => {
        clearTimeout(debounceTimeout)
        debounceTimeout = setTimeout(resolve, waitTime)
    })

    // do stuff here only on the last event after waiting for "waitTime"
}

所以上面的例子完全符合我的要求,但是,对于敏锐的眼睛,你可能会在最终事件无限期 "awaited" 之前意识到一切,这(我假设)是内存泄漏,因为它将继续创造永远不会解决的新承诺。

基本上我想知道是否有任何通用的方法来进行功能相同但没有内存泄漏的谴责。如果可以以某种方式将其清理成一个简单的 await debounce(timeInMS) 调用,则可获得加分。

P.S。我在想也许是拒绝永远无法解决的超时问题,但我不确定这是否是一个好方法。

P.S.S.我知道我要问的事情可以通过跟踪事件并检查在等待该事件 5 秒后是否发生了新事件来有效地完成,如果我需要那样做,那就这样吧。也就是说,这将是我正在处理的应用程序中的一种常见模式,我想要一些更简洁的东西,并希望这个想法不会太过分。

对于这个用例,promises 不是理想的机制:

  1. 事件触发代码通常不期望返回承诺。它只是广播。

  2. 当新事件在等待时间到期之前到达时,您需要 "cancel" 承诺。您可以通过解决或拒绝该特定承诺来做到这一点,但是您仍然必须将该结果与该承诺的正常解决方案区分开来。所需的代码似乎不太优雅。但我会让你来判断(见下文)

  3. setTimeout 本身似乎已经做得很好了

以下是同一演示的两个备选方案。它以随机间隔触发事件。输出为它们中的每一个显示一个点。当等待超时在下一个事件到来之前到期时,在输出中开始一个新行:

使用 promises 的演示

const waitTime = 700;

async function onEvent() {
    // do stuff here on every event
    log.textContent = "." + log.textContent;
    
    if (onEvent.resolve) onEvent.resolve(true);
    
    if (await new Promise(resolve => {
        onEvent.resolve = resolve; // Get a handle to resolve this promise preemptively
        setTimeout(resolve, waitTime);
    })) return; // Promise was resolved before timeout happened

    // Do stuff here only on the last event after waiting for "waitTime"
    log.textContent = "\n" + log.textContent.replace(/\n|$/, "completed\n");
}

// Demo
setRandomInterval(onEvent, 1, 1000);

// Utility function for triggering an event at irregular intervals
function setRandomInterval(cb, min, max) {
    let timeout = setTimeout(() => {
        cb();
        timeout = setRandomInterval(cb, min, max);
    }, min + Math.random()*(max-min));
    return () => clearTimeout(timeout);
}
<pre id="log"></pre>

没有承诺的演示

const waitTime = 700;

function onEvent() {
    // do stuff here on every event
    log.textContent = "." + log.textContent;
    
    clearTimeout(onEvent.debounceTimeout);
    onEvent.debounceTimeout = setTimeout(() => {
        // Do stuff here only on the last event after waiting for "waitTime"
        log.textContent = "\n" + log.textContent.replace(/\n|$/, "completed\n");
    }, waitTime);
}

// Demo
setRandomInterval(onEvent, 1, 1000);

// Utility function for triggering an event at irregular intervals
function setRandomInterval(cb, min, max) {
    let timeout = setTimeout(() => {
        cb();
        timeout = setRandomInterval(cb, min, max);
    }, min + Math.random()*(max-min));
    return () => clearTimeout(timeout);
}
<pre id="log"></pre>