JavaScript通用Async / Await“反跳”

时间:2018-10-19 12:27:57

标签: javascript node.js 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"
}

因此,上面的示例完全按照我想要的方式工作,但是,敏锐的发现,您可能会无限期地意识到最终事件“等待”之前的一切(我假设)是内存泄漏,因为它将继续创建新的承诺永远不会解决。

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

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

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

1 个答案:

答案 0 :(得分:2)

对于这种用例,承诺不是理想的机制:

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

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

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

以下是针对同一演示的两种选择。它以随机间隔触发事件。输出为其中每个显示一个点。当等待超时在下一个事件发生之前到期时,将在输出中开始新行:

使用承诺进行演示

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>