Node.js 如果套接字收到某些请求,则在时间之前执行setTimeout函数

Node.js 如果套接字收到某些请求,则在时间之前执行setTimeout函数,node.js,socket.io,Node.js,Socket.io,我有一个用例,我在20秒后执行setTimeout函数,但是如果前端的套接字连接在20秒之前返回了一些东西,我希望该函数被执行。在这种情况下,我不希望它在20秒后运行。我怎样才能做到这一点。你几乎没有选择。既然您没有包含任何关于如何管理并发性的代码或信息,那么我将向您展示一种使用承诺的合理方法 let resolve; let promise = new Promise(res => resolve = res); // function to call after max 2s or

我有一个用例,我在20秒后执行setTimeout函数,但是如果前端的套接字连接在20秒之前返回了一些东西,我希望该函数被执行。在这种情况下,我不希望它在20秒后运行。我怎样才能做到这一点。

你几乎没有选择。既然您没有包含任何关于如何管理并发性的代码或信息,那么我将向您展示一种使用承诺的合理方法

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秒超时触发之前调用假响应处理程序,则会在调用假响应处理程序之后调用该函数;如果是第一次超时,则会在超时之后立即调用该函数。

这里最简单的方案是将代码放入与
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();
}

承诺在这里可以提供一些好处,因为它们已经确保一个给定的承诺只被解决或拒绝一次,并且可以在这里利用。为了优雅地使用它们,我可能会创建一个小state对象,使其使用起来非常简单

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@PatrickRoberts-我也添加了一个基于承诺的实现,只是为了展示如何干净地完成它。这里当然不需要承诺,但它们做了一些有用的事情,可以在这里使用。更新不错,但是你的
cancel()
实际上并没有取消:哦,等等,我忘记了。这是一种奇怪的方法,我个人会做一些不同的事情,但它确实有效。@PatrickRoberts-
.cancel()
拒绝承诺,这意味着承诺永远无法到达它的
。然后()
处理程序,所以它永远不会调用
fn()
。它确实取消了。还可以防止将来的
.runNow()
方法调用执行任何操作。如果这是你要找的,我没有费心去停止计时器。当计时器触发时,它调用
resolve()
,这对已解析或拒绝的承诺不起任何作用。只是想利用承诺的单向状态转换来免费获得一些功能。是的,我发现了。我花了一秒钟的时间才记住,在这种情况下,
resolve()
不会起任何作用,这就是断开连接的地方。