如何在node.js中休眠线程而不影响其他线程?

时间:2012-11-19 05:50:55

标签: multithreading node.js asynchronous

根据Understanding the node.js event loop,node.js支持单线程模型。这意味着如果我向node.js服务器发出多个请求,它将不会为每个请求生成一个新线程,而是逐个执行每个请求。这意味着如果我在node.js代码中为第一个请求执行以下操作,同时在节点上有新请求,则第二个请求必须等到第一个请求完成,包括5秒休眠时间。正确?

var sleep = require('sleep');
    sleep.sleep(5)//sleep for 5 seconds

node.js是否可以为每个请求生成一个新线程,以便第二个请求不必等待第一个请求完成,或者我是否只能在特定线程上调用sleep?

4 个答案:

答案 0 :(得分:117)

如果您指的是npm模块sleep,它在自述文件中指出sleep将阻止执行。所以你是对的 - 这不是你想要的。相反,您希望使用非阻塞的setTimeout。这是一个例子:

setTimeout(function() {
  console.log('hello world!');
}, 5000);

对于任何希望使用es7 async / await执行此操作的人,此示例应该有所帮助:

const snooze = ms => new Promise(resolve => setTimeout(resolve, ms));

const example = async () => {
  console.log('About to snooze without halting the event loop...');
  await snooze(1000);
  console.log('done!');
};

example();

答案 1 :(得分:2)

如果您在每个请求中都有一个异步请求的循环,并且您希望在每个请求之间有一定的时间,则可以使用此代码:

   var startTimeout = function(timeout, i){
        setTimeout(function() {
            myAsyncFunc(i).then(function(data){
                console.log(data);
            })
        }, timeout);
   }

   var myFunc = function(){
        timeout = 0;
        i = 0;
        while(i < 10){
            // By calling a function, the i-value is going to be 1.. 10 and not always 10
            startTimeout(timeout, i);
            // Increase timeout by 1 sec after each call
            timeout += 1000;
            i++;
        }
    }

此示例在每个请求之后等待1秒,然后发送下一个请求。

答案 2 :(得分:1)

请考虑 deasync 模块,我个人不喜欢Promise方式使所有函数异步,并且关键字async / await anythere。我认为官方node.js应该考虑公开事件循环API,这将简单地解决回调地狱。 Node.js是一个框架而不是一种语言。

var node = require("deasync");
node.loop = node.runLoopOnce;

var done = 0;
// async call here
db.query("select * from ticket", (error, results, fields)=>{
    done = 1;
});

while (!done)
    node.loop();

// Now, here you go

答案 3 :(得分:0)

在使用第三方库(例如Cloud Firestore)提供的异步函数或可观察变量时,我发现函数如下所示的waitFor方法(TypeScript,但您知道了...)会有所帮助当您需要等待某个过程完成时,但又不想将回调嵌入到回调内的回调中,也不必冒险陷入无限循环。

此方法有点类似于while (!condition)睡眠循环,但是 异步产生,并定期对完成条件进行测试,直到达到true或超时为止。

export const sleep = (ms: number) => {
    return new Promise(resolve => setTimeout(resolve, ms))
}
/**
 * Wait until the condition tested in a function returns true, or until 
 * a timeout is exceeded.
 * @param interval The frenequency with which the boolean function contained in condition is called.
 * @param timeout  The maximum time to allow for booleanFunction to return true
 * @param booleanFunction:  A completion function to evaluate after each interval. waitFor will return true as soon as the completion function returns true.   
 */
export const waitFor = async function (interval: number, timeout: number,
    booleanFunction: Function): Promise<boolean> {
    let elapsed = 1;
    if (booleanFunction()) return true;
    while (elapsed < timeout) {
        elapsed += interval;
        await sleep(interval);
        if (booleanFunction()) {
            return true;
        }
    }
    return false;
}

您要在执行其他任务之前先完成一个长期运行的后端流程。例如,如果您有一个总计帐户列表的函数,但是想要在计算之前从后端刷新帐户,则可以执行以下操作:

async recalcAccountTotals() : number {
     this.accountService.refresh();   //start the async process.
     if (this.accounts.dirty) {
           let updateResult = await waitFor(100,2000,()=> {return !(this.accounts.dirty)})
     }
 if(!updateResult) { 
      console.error("Account refresh timed out, recalc aborted");
      return NaN;
    }
 return ... //calculate the account total. 
}