如何创建非阻塞异步函数?以下是我想要实现的目标,但我的程序仍在阻止...
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");
答案 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上找到一个新的
答案 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);
不是“阻塞”,它只是忙着,永远。