node .js建立在libuv之上,这是一个跨平台库,它为支持的操作系统(至少包括Unix、OS X和Windows)提供的异步(非阻塞)输入/输出抽象API/syscall.
异步io
在这个编程模型中,对文件系统don't block the calling thread管理的设备和资源(套接字、文件系统等)执行打开/读/写操作(与典型的同步类c模型一样),只需标记进程(在内核/OS级数据 struct 中),以便在新数据或事件可用时通知.对于类似web服务器的应用程序,流程负责确定通知事件属于哪个请求/上下文,并从那里继续处理请求.请注意,这必然意味着您将处于与向操作系统发出请求的堆栈帧不同的堆栈帧上,因为后者必须向进程的调度程序屈服,以便单线程进程处理新事件.
我描述的模型的问题是,它并不熟悉,程序员也很难推理,因为它本质上是非顺序的."您需要在函数A中发出请求,并在另一个函数中处理结果,而在该函数中,您来自A的本地人通常不可用."
node 的模型(延续传递样式和事件循环)
Node通过 bootstrap 程序员采用某种编程风格,利用javascript的语言特性来解决这个问题,使这个模型看起来更同步.每个请求IO的函数都有一个function (... parameters ..., callback)
这样的签名,需要给它一个回调,在请求的操作完成时调用(请记住,大部分时间都花在等待操作系统发出完成信号上——这段时间可以用来做其他工作).Javascript对闭包的支持允许您使用在回调主体内部的外部(调用)函数中定义的变量——这允许在 node 运行时独立调用的不同函数之间保持状态.另见第Continuation Passing Style页.
此外,在调用生成IO操作的函数后,调用函数通常会将return
个控件发送到 node 的event loop.该循环将调用计划执行的下一个回调或函数(很可能是因为操作系统通知了相应的事件)——这允许并发处理多个请求.
您可以将 node 的事件循环想象为somewhat similar to the kernel's dispatcher:一旦挂起的IO完成,内核将安排执行一个阻塞的线程,而 node 将在相应的事件发生时安排回调.
高度并发,没有并行性
最后一句话,短语"除代码外,所有东西都并行运行"很好地说明了一点,即node允许代码通过在单个执行流中对所有js逻辑进行多路复用和排序,同时处理来自hundreds of thousands open socket with a single thread的请求(尽管这里说"所有东西都并行运行"可能不正确——请参阅Concurrency vs Parallelism - What is the difference?).这对于webapp服务器来说非常有效,因为大多数时间实际上都花在等待网络或磁盘(数据库/套接字)上,而且逻辑不是真正的CPU密集型——也就是说:this works well for IO-bound workloads.