80

根据了解 node.js 事件循环,node.js 支持单线程模型。这意味着如果我向 node.js 服务器发出多个请求,它不会为每个请求生成一个新线程,而是会一个一个地执行每个请求。这意味着如果我在我的 node.js 代码中对第一个请求执行以下操作,同时一个新请求进入节点,第二个请求必须等到第一个请求完成,包括 5 秒的睡眠时间。正确的?

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

node.js 有没有办法为每个请求生成一个新线程,这样第二个请求就不必等待第一个请求完成,或者我可以只在特定线程上调用 sleep 吗?

4

4 回答 4

169

如果您指的是 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();
于 2012-11-19T06:01:23.317 回答
1

请考虑deasync模块,我个人不喜欢 Promise 使所有函数异步的方式,以及任何那里的关键字 async/await。而且我认为官方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
于 2018-05-13T08:34:09.600 回答
1

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

   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 秒。

于 2017-04-28T15:45:36.300 回答
0

当使用 3rd 方库(例如 Cloud firestore)提供的异步函数或 observables 时,我发现函数waitFor如下所示的方法(TypeScript,但你明白了......)当你需要等待某个进程时很有帮助完成,但您不想在回调内的回调中嵌入回调,也不想冒无限循环的风险。

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

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. 
}
于 2020-05-26T18:40:01.343 回答