解释节点callback和单线程
节点的javascript环境是单线程的,还是一切发生在同一时间? 或者(更可能的是)这些语句都不能解释节点上正在发生的事情。
我是新来的节点,并试图了解它如何处理callback。 我在这个主题上的search并没有被certificate是有效的,似乎有多个受众使用像“线程,locking和单线程”这样的术语,为每个观众使用不同的上下文,而且我没有足够的经验来正确parsing节点我在读什么
从我读到的节点的JavaScript执行环境,就像浏览器的单线程。 也就是说,尽pipe一切都是围绕asynchronouscallback来devise的,但所有事情都是以确定性的顺序进行的,并且没有两个线程同时修改同一个variables或者运行语句。 我也读过这意味着节点程序员 – 用户不必担心locking语义。
如果我在浏览器的土地,并使用其中一个stream行的JavaScript库来build立一个非DOM事件处理程序的callback,像
console.log("Here"); $.each([1,2,3],function(){ console.log("-- inside the callback --"); }); console.log("There");
我的输出是一贯的
Here -- inside the callback -- -- inside the callback -- -- inside the callback -- There
但是,如果我使用节点js中的callback来执行此类操作(从命令行将其作为shell脚本运行)
var function example() { var fs = require('fs'); console.log("Here"); fs.readdir('/path/to/folder', function(err_read, files){ console.log('-- inside the callback --'); }); console.log("There"); for(var i=0;i<10000;i++) { console.log('.'); } } example(); console.log("Reached Top");
我始终如一(看起来 – 看到“没有太多的经验”上面)得到这样的结果
Here There . . (repeat 10,000 times) Reached Top -- inside the callback --
也就是说,节点在调用callback函数之前完成函数example
。
这是节点中的确定性行为吗? 或者在example
函数完成之前有时候会调用callback函数? 还是会依赖于库中使用callback的实现?
我明白节点背后的想法是编写基于事件的代码 – 但我试图了解什么节点真的在做什么,哪些行为可以依赖,什么不可以。
在这种情况下,您正在调用正在执行IO的function并且是asynchronous的。 这就是为什么你看到你的方式输出。
因为其余的代码正在内联执行 – 在单个执行线程上,它是在IO事件有机会进入事件循环之前完成的。
我会说,期待这种行为,但不要绝对依靠它,因为它取决于使用callback函数库的实现。 一个(坏的,邪恶的)实现者可能正在做一个同步的请求,看是否有任何工作要做,如果没有,立即callback。 (希望你永远不会看到这个,但是…)。
节点的javascript环境是单线程的,还是一切发生在同一时间?
Node具有单线程的程序执行模式,这意味着在一个节点进程中,任何时候只能执行一条指令。 执行将继续,直到程序产生控制。 这可能发生在程序代码的末尾,或者当callback到达结束时。
在第一种情况下:
console.log("Here"); $.each([1,2,3],function(){ console.log("-- inside the callback --"); }); console.log("There");
他们的关键是$.each
同步使用callback,所以有效地调用callback以确定性的顺序。
现在在第二种情况下, fs.readdir
asynchronous使用callback – 它将等待事件的callback触发(即读取目录结束时)。 这可以随时发生。 但是,调用函数不会产生控件,所以在调用任何callback之前, example
总是会完成。
一句话:函数/全局作用域的所有代码在该函数/全局作用域中定义的任何callback之前执行。
我想补充一点到@ dc5的答案。 在它的网站上,他们将节点描述为
Node.js使用事件驱动的非阻塞I / O模型
事件驱动部分非常重要。 当我无法理解节点程序的执行模型时,通常会清除我的疑惑。
举个例子,发生的事情是:
-
这里是打印到控制台。
-
对这些文件进行asynchronous调用。
-
节点将侦听器附加到asynchronous调用。
-
继续执行线,并打印。
现在可能是asynchronous调用在正在执行的当前代码片段之前完成,但是节点js完成了手头的任务,然后返回服务于asynchronous调用。
所以不要等待任何事情继续执行。 这就是为什么节点js执行循环从不空闲的原因。