我有一个用例,我在20秒后执行setTimeout函数,但是如果前端的套接字连接在20秒之前返回了某些内容,我希望执行该函数。在这种情况下,我不希望它在20秒后运行。我怎样才能做到这一点。
答案 0 :(得分:1)
这里最简单的方案是将代码放在与setTimeout()
一起使用的函数中,如果定时器仍在运行,则取消定时器并直接调用函数:
function doSomeTask() {
// code here for your task
}
// schedule task to run in 20 seconds
// remember timer handle so we know it's running
let timer = setTimeout(() => {
timer = null;
doSomeTask();
}, 20*1000);
// elsewhere in your code where you want to call your function
// earlier than the timer (if it hasn't already been called)
if (timer) {
clearTimeout(timer);
timer = null;
doSomeTask();
}
Promise可以在这里提供一些好处,因为他们已经确保给定的承诺只能被解决或拒绝一次,并且可以利用这里。为了优雅地使用它们,我可能会创建一个使其非常简单的状态对象。
function delayExecute(fn, t) {
let obj = {state: "timer"};
let p = new Promise((resolve, reject) => {
obj.runNow = resolve;
obj.cancel = reject;
setTimeout(resolve, t);
}).catch(err => {
obj.state = "err";
throw err;
}).then(() => {
fn();
obj.state = "done";
});
return obj;
}
function doSomeTask() {
// code here for your task
}
let task = delayExecute(doSomeTask, 20*1000);
// then some time later, to run it sooner (if it hasn't already run)
// calling the .runNow() method after the function has already run will do nothing
task.runNow();
同样的界面也可以在没有承诺的情况下构建。我只是想我会展示如何为此目的利用承诺的单向状态转换。
答案 1 :(得分:0)
你没有多少选择。由于您没有包含有关如何管理并发性的任何代码或信息,因此我将向您展示使用承诺似乎合理的一种方式。
let resolve;
let promise = new Promise(res => resolve = res);
// function to call after max 2s or after response
let fn = () => {
console.log(process.uptime(), 'Function called');
};
// the timeout:
setTimeout(resolve, 1000);
// the fake response handler:
setTimeout(() => {
console.log(process.uptime(), 'Request returned');
resolve();
}, 2000 * Math.random());
promise.then(fn);
then
处理程序只运行一次。多次执行该程序,如果在1秒超时触发之前调用伪响应处理程序,则会在调用伪响应处理程序之后立即调用该函数,如果超时是第一个,则立即调用该函数。