JavaScript универсальный Async / Await "debounce" - PullRequest
0 голосов
/ 19 октября 2018

Так что в основном у меня есть асинхронный обратный вызов события, который иногда срабатывает довольно быстро.То, что я хочу сделать, - это выполнить некоторые методы прямо тогда, но затем подождать некоторое время после последнего четного вызова, прежде чем выполнить последний бит кода.

Вот пример:

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).

PS Я подумал, может быть, что-то вроде отклонения таймаутов, которое никогда не будет решено, но я не уверен, что это будетбудь хорошим подходом.

PSS Я знаю, что то, что я спрашиваю, можно эффективно сделать, отслеживая события и проверяя, произошло ли новое после ожидания 5 секунд на этом, и если мне нужноидти по этому пути, пусть будет так.Тем не менее, это будет распространенный шаблон в приложении, над которым я работаю, и я хотел бы что-то немного чище, и надеялся, что эта идея не слишком много.

1 Ответ

0 голосов
/ 19 октября 2018

Для этого варианта использования обещания не являются идеальным механизмом:

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

Демонстрация без обещаний

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