Nodejs简介

Nodejs简介

Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient. Node.js' package ecosystem, npm, is the largest ecosystem of open source libraries in the world.

Node.js是服务端JavaScript环境,是服务器关键功能的基础,比如二进制数据操作、文件I/O操作、数据库访问、计算机网络等等。它有一些独一无二的特性,使得它在众多现有的成熟框架中凸显出来,比如Django (Python), Laravel(PHP), RoR (Ruby)等等。一些技术公司 PayPal, Tinder, Medium,LinkedIn, Netflix因为这些特性而使用它,有些甚至在1.0版本就已经开始使用。

Node.js Architecture

Nodejs简介_第1张图片
nodejs架构图Application/Modules:这里是所有JavaScript代码,你的应用代码,Node.js核心模块,你从npm安装的任何模块,和你写的所有模块。是你工作的主要部分

Bindings:这时候你可能会发现Node.js是用JavaScript和C/C++写的。bindings把Node.js内部的C/C++类库(c-ares, zlib, OpenSSL, http-parser等)暴露给JavaScript,写bindings的一个动机是代码复用,另一个动机是性能(CPU密集操作)

C/C++ Addons:Bindings只对Node.js的内部核心类库绑定,比如zlib, OpenSSL, c-ares, http-parser等等。如果想引入第三方的C/C++类库到你的应用,就必须自己写绑定代码。自己写的绑定代码叫做addons。可以把bindings、addons当做JavaScript和C/C++之间的“桥梁”。

V8:高性能JavaScript执行引擎,是谷歌开源软件,C++语言实现。它也是Chrome浏览器的内部引擎。JavaScript脚本被V8编译成机器码(因此非常快),然后执行。

libuv: 异步特性的C语言库。它包含时间轮询,线程池,文件系统事件和一些提供关键功能的子进程。

其他C/C++组件:比如c-ares,crypto(OpenSSL),http-parser,zlib。这些底层组件的交互为服务器提供网络、压缩和编解码等重要功能

Nodejs工作流

一个Node.js应用启动,V8引擎开始执行你写的代码。应用中的对象(注册事件的函数)会变成一系列的观察者。事件发生的时候,相应的观察者会得到通知。

事件发生,观察者的回调函数会被加入消息队列 。只要消息队列有数据,循环函数 会不停取出它们压入执行堆栈 。注意,只有先前的消息处理完成循环函数 才会把下一个压入执行堆栈 。

执行堆栈中,如果发生I/O操作,会把它移交到libuv处理。libuv默认包含一个有四个工作线程的线程池,线程的数量可以设置。工作线程通过和Node.js的底层类库交互来执行比如数据传输、文件访问等操作。libuv处理完后再把事件加入消息队列,Node.js主线程继续处理。libuv以异步方式处理,Node.js主线程不会等待处理结果而是继续执行。libuv处理完成,加入消息队列,循环函数再次把事件压入执行堆栈,这就是Node.js一个消息处理的生命周期。

Nodejs简介_第2张图片

CPU密集型任务

因为event loop在处理所有的任务/事件时,都是沿着事件队列顺序执行的,所以在其中任何一个任务/事件本身没有完成之前,其它的回调、监听器、超时、nextTick()的函数都得不到运行的机会,因为被阻塞的event loop根本没机会处理它们,此时程序最好的情况是变慢,最糟的情况是停滞不动,像死掉一样。所以当Node.js遇到高CPU占用率的任务时,event loop会被阻塞住,形成下面这种局面:

Nodejs简介_第3张图片

CPU密集型任务处理方法

被闲置的CPU内核

Node.js是单线程程序,它只有一个event loop,也只占用一个CPU/内核。现在大部分服务器都是多CPU或多核的,当Node.js程序的event loop被CPU密集型的任务占用,导致有其它任务被阻塞时,却还有CPU/内核处于闲置的状态,造成资源的浪费。

把CPU密集型任务分给子线程

child_process.fork() 得到的并不是子进程,而是一个全新的Node.js程序实例,新开进程,通过IPC通信,将CPU密集型任务交给子进程,子进程计算完毕后,再通过ipc消息通知主进程,并将结果返回给主进程

并且每个新实例至少需要30ms的启动时间和10M内存,也就是说通过fork()繁衍进程,不光是充分利用了CPU,也需要很多内存,所以不能fork()太多。进程间通信效率也不高

Cluster

A single instance of Node.js runs in a single thread. To take advantage of multi-core systems the user will sometimes want to launch a cluster of Node.js processes to handle the load.

addon

不开进程,而是将CPU耗时操作交给进程内的一个工作线程完成。

基本模块

因为Node.js是运行在服务区端的JavaScript环境,服务器程序和浏览器程序相比,最大的特点是没有浏览器的安全限制了,而且,服务器程序必须能接收网络请求,读写文件,处理二进制内容,所以,Node.js内置的常用模块就是为了实现基本的服务器功能。这些模块在浏览器环境中是无法被执行的,因为它们的底层代码是用C/C++在Node.js运行环境中实现的。

global

JavaScript有且仅有一个全局对象,在浏览器中,叫window对象。而在Node.js环境中,也有唯一的全局对象,但不叫window,而叫global,这个对象的属性和方法也和浏览器环境的window不同。

process

process也是Node.js提供的一个对象,它代表当前Node.js进程。JavaScript程序是由事件驱动执行的单线程模型,Node.js也不例外。Node.js不断执行响应事件的JavaScript函数,直到没有任何响应事件的函数可以执行时,Node.js就退出了。

判断JavaScript执行环境

有很多JavaScript代码既能在浏览器中执行,也能在Node环境执行,但有些时候,程序本身需要判断自己到底是在什么环境下执行的,常用的方式就是根据浏览器和Node环境提供的全局变量名称来判断:

fs

stream

http

crypto

Nodejs开发桌面应用

通过JavaScript、HTML、CSS开发跨平台的桌面化应用

Node-webkit

Electron



参考:

https://medium.com/yet-another-node-js-blog/architecture-of-node-js-internal-codebase-57cd

http://www.liaoxuefeng.com/

你可能感兴趣的:(Nodejs简介)