Как очистить тайм-аут для асинхронной функции в JavaScript - PullRequest
0 голосов
/ 13 января 2020

Позвольте мне быть очень ясным, чтобы избежать путаницы. У меня есть функция сна (ниже), время ожидания которой составляет столько миллисекунд, сколько я укажу.

function sleep(ms) 
{
    return new Promise(resolve => setTimeout(resolve, ms));
}

Теперь в другой функции beginTest () я вызывал сон в течение некоторой миллисекунды, скажем, 5000 мс.

async function beginTest()
{
    await sleep(5000);
}

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

document.getElementById("reactTimeClick").onmousedown = function()
{
    cleartimeOut(); // Clear timeout of above function
}

1 Ответ

0 голосов
/ 13 января 2020

Это довольно просто сделать, как вы предлагаете, с помощью «токена отмены», с помощью которого «тайм-аут сна» может быть отменен:

// don't do this
function sleep(ms, cancellationToken) {
    return new Promise(resolve => function() {
        let timeoutRef = setTimeout(resolve, ms);
        cancellationToken.cancel = function() {
            clearTimout(timeoutRef);
        };
    });
}

Однако это само по себе не вызовет обещание сна покинуть его pending состояние, и цепочка обещаний (или ожидающих заявлений), вытекающая из sleep(), не будет проинформирована об отмене. Прогресс будет зависать.

Этот недостаток можно преодолеть, опять же с помощью токена отмены, но на этот раз тот, который позволяет обещанию sleep() быть отклоненным, следующим образом ...

// do this
function sleep(ms, cancellationToken) {
    return new Promise((resolve, reject) => function() {
        cancellationToken.cancel = function() {
            reject(new Error('sleep() cancelled'));
        };
        setTimeout(resolve, ms));
    }
}

... и в вызывающей стороне используйте следующее:

async function beginTest() {
    try {
        const token = {};
        const promise = sleep(5000, token);
        $('#cancelButton').on('click', token.cancel); // jQuery example, or similar in POJS
        await promise;
        // ... test code ...
        // ... return whatever;
    }
    catch(error) {
        console.log(error.message);
        // If button was clicked before the 5000 ms has expired, 
        // and no other error has been thrown, 
        // then the log will show "sleep() cancelled".
        throw error; // rethrow error to keep beginTest's caller informed.
    }
}
...