如何在不影响其他线程的情况下使 node.js 中的线程休眠?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13448374/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 16:40:26  来源:igfitidea点击:

How to sleep the thread in node.js without affecting other threads?

multithreadingnode.jsasynchronous

提问by emilly

As per Understanding the node.js event loop, node.js supports a single thread model. That means if I make multiple requests to a node.js server, it won't spawn a new thread for each request but will execute each request one by one. It means if I do the following for the first request in my node.js code, and meanwhile a new request comes in on node, the second request has to wait until the first request completes, including 5 second sleep time. Right?

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

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

Is there a way that node.js can spawn a new thread for each request so that the second request does not have to wait for the first request to complete, or can I call sleep on specific thread only?

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

回答by David Weldon

If you are referring to the npm module sleep, it notes in the readme that sleepwill block execution. So you are right - it isn't what you want. Instead you want to use setTimeoutwhich is non-blocking. Here is an example:

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

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


For anyone looking to do this using es7 async/await, this example should help:

对于希望使用 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();

回答by Jodo

In case you have a loop with an async request in each one and you want a certain time between each request you can use this code:

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

   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++;
        }
    }

This examples waits 1 second after each request before sending the next one.

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

回答by Sunding Wei

Please consider the deasyncmodule, personally I don't like the Promise way to make all functions async, and keyword async/await anythere. And I think the official node.js should consider to expose the event loop API, this will solve the callback hell simply. Node.js is a framework not a language.

请考虑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

回答by user1023110

When working with async functions or observables provided by 3rd party libraries, for example Cloud firestore, I've found functions the waitFormethod shown below (TypeScript, but you get the idea...) to be helpful when you need to wait on some process to complete, but you don't want to have to embed callbacks within callbacks within callbacks nor risk an infinite loop.

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

This method is sort of similar to a while (!condition)sleep loop, but yields asynchronously and performs a test on the completion condition at regular intervals till true or timeout.

这种方法有点类似于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;
}

The say you have a long running process on your backend you want to complete before some other task is undertaken. For example if you have a function that totals a list of accounts, but you want to refresh the accounts from the backend before you calculate, you can do something like this:

假设您在后端有一个长时间运行的进程,您希望在执行其他任务之前完成。例如,如果您有一个汇总帐户列表的函数,但您想在计算之前从后端刷新帐户,您可以执行以下操作:

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. 
}