2010-05-20 79 views
21

如何创建一个非阻塞异步函数?下面是我想要实现,但我的程序仍在拦截...如何在node.js中创建一个非阻塞异步函数?

var sys = require("sys"); 

function doSomething() { 
    sys.puts("why does this block?"); 
    while(true); 
} 

setTimeout(doSomething,0); 
setTimeout(doSomething,0); 
setTimeout(doSomething,0); 

sys.puts("main"); 

回答

3

setTimeout不会创建一个新线程,因此浏览器仍然挂在无限循环。

您需要重新考虑您的程序结构。

+0

你知道我在node.js中如何实现这个功能吗?谢谢 – Richard 2010-05-20 21:37:58

+1

这个问题很老旧,但对于像我这样的node.js初学者来说,仍然非常有趣。如前所述,node.js是针对并行I/O而非并行工作的。这意味着:如果你有一个耗时的工作来响应单个请求node.js不会加快你在单个请求中尝试实现的内容。 使用sleep()和setTimeout()之间的区别在于,当使用sleep()进行睡眠时,node.js将阻止所有其他请求 - 使用setTimeout()将不会阻止其他请求。或者:10个睡眠请求(10s)将需要100s - 10个请求setTimeout(10s)只需10s。 – schlicki 2016-03-04 19:49:54

10

您需要在单独的进程中运行阻塞函数。

该模块可以帮助:http://github.com/cramforce/node-worker

+26

重要的是要明白,节点并不是一直处于异步的函数。它关于* i/o *是异步和非阻塞的。如果你的函数没有做任何i/o,节点不会帮你使它异步。它提供的工具可以让你做到这一点。像子进程一样。这就是费利克斯的答案。你的函数可以派生一个子进程来完成你的工作,它将在主事件循环中执行。 – Marco 2010-05-22 14:23:04

-6

这条线:

while(true); 

不是 “堵”,它只是忙,直到永远。

4

如果您不想使用WebWorker API/node-worker(仍然非常简单),只需创建其他节点程序并通过TCP或HTTP进行通信即可。

这使您可以将工作分配为HTTP调用或原始TCP数据,并异步等待HTTP响应/传入TCP答案。

但是请注意,只有在您的任务很容易序列化时才适用。

11

通过使用由C++编写的node.js运行时或node.js扩展提供的异步IO函数,您只能在node.js中执行异步IO。您自己的Javascript代码在node.js中始终是同步的。异步非IO代码很少需要,而node.js设计者决定完全避免它。

在其他评论者提到的node.js中有一些异步运行Javascript的方法,但是node.js并不是为这类工作设计的。如果你需要这种类型的并发性,使用Erlang,node.js只是关于并行IO,而对于并行计算,它与Python或PHP一样糟糕。

+0

很好的回答,我有一个问题:Node.js中的mongo db操作是异步IO吗? – 2014-12-30 09:37:40

+1

是的。例如'.connect'和'.insert'是异步函数。见http://mongodb.github.io/node-mongodb-native/2.0/overview/quickstart/ – nponeccop 2014-12-30 18:15:07

31

交叉从Reddit发布。


JavaScript中异步函数的用途与您寻求的有点不同。

请记住,JavaScript是单线程的 - 它一次只能做一件事。下面是一些传统的,阻塞代码:

sys.puts("Before"); 
sleep(10); 
sys.puts("After"); 

在真实世界中的Web应用程序中,sleep()可能反而是一个耗时的数据库调用,网络请求(如从用户的Web浏览器等待数据),帮手工具或文件访问。

如果您使用类似上述的阻塞调用,则Node.js服务器在等待时无法执行其他任何操作(如开始处理其他Web请求)。

PHP和许多其他Web编程环境通过为每个请求创建完全独立的线程来处理此问题。 Node.js使用回调函数。你可以写相同的代码是这样,而是:

sys.puts("Before"); 
setTimeout(function(){ 
    sys.puts("After"); 
}, 10000); 

在这里,你创建一个函数,并把它传递给setTimeout()。它的代码还没有运行,但是当它运行时,它将访问它创建的所有范围(所有变量)。 setTimeout()获取对该功能的引用,并在超时到期后安排要在the event loop上触发的事件。

事件循环本质上是一个Node.js程序的待办事项列表(它们很常见 - 您的计算机上运行的所有GUI应用程序都可能使用事件循环!)。

呼叫setTimeout()后,当前函数继续执行。它最终返回,并调用它的函数返回,等等,直到程序结束回事件循环。事件循环查看代码执行时是否发生任何事情(例如传入请求),并在代码中调用相应的函数。如果没有,则等待发生(如超时到期)。

异步代码让你的代码在同一时间做很多事情,它消除当一些代码依赖于外在的东西继续阻止。

很少有您需要在Node.js程序中阻止工作。如果你这样做了,你应该把这个工作分解成一个单独的进程(甚至可以是另一个Node.js程序),或者编写可以自由使用线程的a C/C++ addon

+1

啊!现在我更清楚地理解它了。感谢您的解释;你的倒数第三段特别有用。 +1 – 2011-11-04 20:28:44

2

如果我明白你在做什么之后,你有两个函数(都以回调为参数):

process.nextTick:这个函数可以堆叠,这意味着如果它被递归地调用,它会l在事件循环的每个节拍中输入一个巨大的(process.maxTickDepth)次数。

setImmediate:该功能是更接近设定0超时(但发生前)。

在大多数情况下,您应该更喜欢setImmediate。

0

我假设你正在试验Nodejs我也假设你没有写任何npm模块本身并将你的函数导出为异步函数,在实际中你不会遇到这种情况,如果你想做任何阻塞操作在单线程环境中执行的函数或回调函数中,尝试使用适当的节点模块(如fs进行文件读取,请求网络请求以及提供各种类型异步操作的异步模块),还要记住您正在尝试执行cpu消耗代码异步这是一个坏主意,因为2HZ可以在少于几微秒内执行一百万行代码

nodejs的主要目的是解决您在问题中询问的问题,即由底层libuv来处理异步事件,我很欣赏使用set time的答案,但是你不知道等待或使用node worker的时间是多少,但你最终会写很多的boiler plate代码,所以只需搜索可满足您需求的npm模块即可。

相关问题