简体   繁体   English

JavaScript通用Async / Await“反跳”

[英]JavaScript generic Async/Await “debounce”

So basically I've got an async event callback that sometimes fires off quite quickly. 所以基本上我有一个异步事件回调,有时会很快触发。 What Im looking to do is to execute some of the method right then, but then wait until a while after the last even call before executing the final bit of the code. 我想做的就是立即执行一些方法,但是要等到最后一个偶数调用之后的一会儿再执行代码的最后一部分。

here is an example: 这是一个例子:

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"
}

so the above example works exactly how I want however, to the keen eyed, you may realize everything before the final event is being "awaited" indefinitely which (I'm assuming) is a memory leak as it will keep creating new promises that never resolve. 因此,上面的示例完全按照我想要的方式工作,但是,敏锐的眼光,您可能会无限期地意识到在最终事件“等待”之前的所有事情(我假设)是内存泄漏,因为它将不断创建新的承诺,解决。

Basically I'm wondering if there is any generic way to do a denounce that is the same functionally but without the memory leak. 基本上,我想知道是否有任何通用的方法来进行功能相同但没有内存泄漏的谴责。 bonus points if it can be cleaned up somehow into a simple await debounce(timeInMS) call. 如果可以通过某种方式将其清除到简单的await debounce(timeInMS)调用中,则获得加分。

PS I was thinking maybe something along the lines of rejecting timeouts that will never be resolved, but I'm not sure if that would be a good approach. PS:我在想也许拒绝超时的事情永远不会解决,但是我不确定这是否是一个好方法。

PSS I know what I'm asking can effectively be done by keeping track of the events and checking if a new one has occurred after waiting the 5 seconds on that one, and if I need to go that way, so be it. PSS我知道我要问的是可以通过跟踪事件并在等待5秒钟后检查是否发生了新事件来有效地完成的,如果我需要这样做,就这样吧。 That said this will be a common pattern in the application I'm working on and I'd like something a little cleaner, and was hoping this idea wasn't to much of a stretch. 就是说,这将是我正在处理的应用程序中的一种常见模式,我想要一些更清洁的东西,并希望这个想法不会太大。

For this use case promises are not the ideal mechanism: 对于这种用例,promise不是理想的机制:

  1. Event triggering code is usually not expecting a promise to be returned. 事件触发代码通常不期望返回承诺。 It just broadcasts. 它只是广播。

  2. You would need to "cancel" a promise when a new event arrives before the waiting time expires. 当新事件到来之前,您需要在等待时间到期之前“取消”承诺。 This you can do by resolving or rejecting that particular promise, but then you must still differentiate that outcome from a normal resolution of that promise. 您可以通过解决或拒绝该特定承诺来做到这一点,但是您仍然必须将该结果与该承诺的正常解决方案区分开。 The code needed for that seems less elegant. 所需的代码看起来不太优雅。 But I'll let you be the judge of that (see below) 但我会让你当法官(见下文)

  3. setTimeout on its own seems to do the job well enough already setTimeout本身似乎已经做好了工作

Below two alternatives for the same demo. 下面是同一演示的两种选择。 It triggers events with random intervals. 它以随机间隔触发事件。 The output shows a dot for every one of them. 输出为其中每个显示一个点。 When the waiting timeout expires before the next event comes in, a new line is started in the output: 当等待超时在下一个事件进入之前到期时,将在输出中开始新行:

Demo using 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> 

Demo without promises 没有承诺的演示

 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> 

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

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