根据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?
答案 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.
}