Calling a function foo that does “something” after N milliseconds set by timeout. If  foo is called again before timeout expires I first cancel timeout - then set new. Simple enough using a global variable for a timer.
Usually that is it, but then I found that in some cases I need to wait for the “something” to finish and then do some follow-up things. From that I assume a promise is the way to go.
Or in more general terms:
How to return a promise from a promise by a timeout that can be cancelled.
After some meddling I have this. Look at sample of how I use it with a second promise:
const promise_time = (ms, old) => {
    let timeout, p = { pending: true };
    if (old && old.pending)
        old.abort();
    p.wait = new Promise(resolve => {
        timeout = setTimeout(() => {
            p.pending = false;
            resolve();
        }, ms);
    });
    p.abort = () => {
        clearTimeout(timeout);
        p.pending = false;
    };
    return p;
};
Using it in combination with a second promise as shown below.
But it feels somewhat clumsy and overly complex; but I do not manage to see for myself if it is. Need fresh eyes :P.
Is there a better way to do this? (rather likely)
Have looked into AbortController but did not find a way that seemed more clean, rather the opposite.
Sample usage:
Below is a dummy example. Just type something in the text box. If keydown delay is < 1s the timeout is cancelled and new set. Else it fires and resolves promise.
The button is meant to resemble the normal procedure, i.e. just do it after a delay.
const promise_time = (ms, old) => {
    let timeout, p = { pending: true };
    if (old && old.pending)
        old.abort();
    p.wait = new Promise(resolve => {
        timeout = setTimeout(() => {
            p.pending = false;
            resolve();
        }, ms);
    });
    p.abort = () => {
        clearTimeout(timeout);
        p.pending = false;
    };
    return p;
};
let timed;
const do_timed_thing = v => {
    // Initiate timer + potentially clear old
    timed = promise_time(1000, timed);
    return new Promise(resolve => {
        timed.wait.then(() => {
            // garbageify object
            timed = null;
            add_li('timed val “' + v + '”');
            resolve();
        });
    });
};
const add_li = txt => {
    let li = document.createElement('LI');
    li.textContent = (new Date()).toLocaleTimeString() + ' ' + txt;
    document.getElementById('ul').appendChild(li);
};
const txt = document.getElementById('txt');
txt.addEventListener('input', () => {
    do_timed_thing(txt.value).then(() => {
        txt.value = '';
        add_li('cleared input');
    });
});
document.getElementById('nop')
.addEventListener('click',() => {
    do_timed_thing('Only something');
});
txt.focus();<div style="display: grid">
<p>Max 1 sec between keystrokes; Do something + something else.</p>
<input id="txt" type="text" placeholder="Do something + something else" />
<hr />
<button id="nop">Do something (after 1 sec) and only that</button>
<ul id="ul"></ul>
</div> 
    