带有promise的可取消超时,返回promise



调用函数foo,该函数在超时设置的N毫秒后执行"某事"。如果在超时到期之前再次调用foo,我首先取消超时-然后设置new。使用全局变量作为计时器非常简单。

通常就是,但后来我发现,在某些情况下,我需要等待"某事">完成,然后做一些后续的事情。从这一点来看,我认为承诺是正确的选择。

或者更一般地说:

如何通过可取消的超时从promise返回一个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;
};

与第二个承诺结合使用,如下所示。

但是感觉有些笨拙和过于复杂;但我不能亲自去看它是不是真的。需要新鲜的眼光:p

有更好的方法吗?(不可能)

我调查了AbortController,但没有找到一种更干净的方法,而是相反。

<标题>

示例用法:下面是一个虚拟的例子。在文本框里输入点什么。如果按键延迟为<1秒超时取消,重新设置。否则它会触发并解析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;
};
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>

我将按如下方法解决这个问题:


// An object that keeps track of the last action timeout and
// cancels it every time a new action gets planned.
const action_planner = {
// This is the last scheduled timeout id.
timeoutId: null, 

setAction (callback, timeout) {
// Cancel the previous action
clearTimeout(this.timeoutId);
// Replace it with the new action
this.timeoutId = setTimeout(callback, timeout);
}
}
element.addEventListener('click', () => action_panner.setAction(do_something, 1000));

感谢@FZs的提示。

最新更新