如何在node.js中创建非阻塞异步函数?

时间:2010-05-20 21:31:04

标签: 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");

10 个答案:

答案 0 :(得分:34)

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 :(得分:17)

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

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

答案 2 :(得分:10)

您需要在单独的过程中运行阻止功能。

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

答案 3 :(得分:4)

如果您不想使用仍然非常alpha的WebWorker API / node-worker,只需创建一个额外的节点程序并通过TCP或HTTP进行通信。

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

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

答案 4 :(得分:3)

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

您需要重新考虑您的计划结构。

答案 5 :(得分:2)

您可以在不使用nextTick()

的子进程的情况下执行此操作

前几天我正在阅读关于nextTick的这个解释...这是一个很好的阅读IMO

---编辑:旧链接死了。在StackOverflow上找到一个新的

understanding the node.js event queue and process.nextTick

答案 6 :(得分:1)

如果我确实理解了你之后的事情,你有两个函数(都以回调作为参数):

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

setImmediate:此函数更接近于设置0超时(但之前发生)。

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

答案 7 :(得分:0)

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

nodejs的主要目的是解决你在底层libuv处理异步事件所处理的问题中提出的问题,我很欣赏使用set time out的答案,但是你不知道要花多少时间等待或使用节点工作者很好,但你最终会编写大量的锅炉板代码,所以只需搜索满足你需要的npm模块。

答案 8 :(得分:0)

尝试基于事件循环模型(node.js的核心)回答这个问题。

setTimeout(doSomething,0)。是的,setTimeout会将一个任务添加到任务队列中。在0秒之后,时间到了。事件循环检查任务队列并发现任务已完成,并且其回调函数doSomething已准备好运行。

上述过程是异步

这里需要注意的一件事是:回调函数doSomething在node.js的主线程(或单线程)上运行,并且事件循环也在该线程上运行。毫无疑问,while(true)循环完全阻塞了线程。

答案 9 :(得分:-5)

这一行:

while(true);

不是“阻塞”,它只是忙着,永远。