Nodejs基础知识整理

                                                                     NodeJS基础知识

 关于Node的火热程度和简介想必也不用多说,这里就简单的描述一下,Nodejs作者Ryan Dahl,初衷是单纯的开发一个Web服务器,但是项目的发展超出了他的预期值。为什么Node要选择JavaScript作为实现的语言,这得益于Chrome的V8引擎的出色性能,CommonJS标准的制定,符合事件驱动,还有一点JavaScript的群众基础大同时门槛相比于C/C++较低,同时尽管服务端JavaScript之前已经存在,但是没有市场,所以没有市场包袱,当然也离不开生态社区中诸多开发者无私的贡献,以上种种造就了Nodejs的火爆。

1. 为什么说Node吞吐量大?

    Node的机制,保留了JavaScript在浏览器中单线程的特点,对于进来的请求不是在后台启动一个线程来单独跟踪 ,而是利用事件轮询机制处理,单独开启一个线程是需要消耗CPU内存的,比如你CPU不行,进来1000个请求,你的CPU就蹦了,所以传统的解决方案就是添加NLB负载均衡来缓解CPU的的压力。但是对于Node来说则会大大改善这一问题,因为它采用的是事件轮询回掉的机制,采用异步I/O 编程,利用单线程,原理多线程死锁,状态同步等问题,同时远离阻塞,更好的利用CPU,这也是Node吞吐量大的原因。

2. 为什么说Node速度快?

    先说一下Node到底有多快,相比于静态语言C和C++还是比不过的,不过也可以说是仅次于那些静态语言。为什么这样说,之前已经简单的说了它的机制是事件轮询和链式回掉,这也是区别于传统的方式,规避掉了多线程并行的方式,减少CPU的消耗,避免了了一些数据共享与死锁的问题,其次,Node的内建模块是有C/C++编写(如下图),说明了Node模块底层的处理速度。再者是Node的缓存机制,对于内建模块再被调用时是直接转化为二进制缓存到本地。

    Nodejs基础知识整理_第1张图片

3. 什么是异步I/O?

    在说异步I/O之前先来明确几个概念,同步/异步, 阻塞/非阻塞,首先同步异步与阻塞非阻塞不是一回事儿,同步/异步没错就是你想的那样,而阻塞和非阻塞是在面向系统内核来说分为阻塞IO/非阻塞IO,区别在于是否会立即返回结果,阻塞的是等完整的IO完成之后返回完整IO,而非阻塞是立即返回IO的状态,然后通过多次重复判断来确认是否完成完整IO,这个重复判断的操作叫做轮询。其实无论阻塞和非阻塞,都有自己的缺点,期待的完美的异步IO示意图应该如下,不浪费任何CPU资源同时完成完整IO的时还能及时返回。

Nodejs基础知识整理_第2张图片

    其实也就是Windows下IOCP异步I/O模型,Linux下是另一种相似的模型暂不去探讨,在IOCP之上,Node提供了Libuv作为抽象封装层,同时兼容多平台。

4. 什么是Node的事件轮询(Event Loop)?

    在说Node事件轮询之前,咱们先了解一下JavaScript的事件轮询(在浏览器中的行为)。在JavaScript中的事件轮询说白了就是方法以参数的形式被传递,然后以同步的方式执行方法,也就是常说的callback,执行在单线程上。

    还要补充先说明一下Node的单线程其实是在执行JavaScript的时候是单线程,Node自身时候有线程池的概念的,类似有web worker的子线程。Node的事件轮询是在进程启动时,Node便会创建一个类似与While(true)的循环,每执行一次循环成为一个次Tick,在Tick的过程中查看是否有事件需要被处理,如果有就取出事件和相关的callback,然后执行,再之后下一次循环重复相同动作。不过这里的事件由来是很复杂的过程,首先从我们调用开始到系统内核会一个叫做请求对象的概念,也就是libuv封装层根据具体平台创建一个适合与具体平台应用的一个对象例如windows的FSReqWrap请求对象,然后会把我们调用的方法的参数和callback函数添加到这个生成的对象的属性上,然后调用相应的底层函数,当前I/O操作也就再线程池中等待执行了,我们调用的JavaScript被函数被立即返回,不会阻塞后续的JavaScript操作,至此咱们这个调用完成了第一部分。而我们最关心的是刚才被添加到底层对象属性上的callback函数,callback函数会在什么时候执行那?其实是这样的,刚才我们的I/O操作已经是在线程池中处于被等待执行的状态,如果现在有空闲的线程就会执行我们的操作,我们的操作结果会被存在FSReqWrap的result属性上,然后调用PostQueuedCompletetionStatus()同时给IOCP,然后每次Tick的时候调用GetQueuedCompletionStatus()方法来检查县城时候是否有执行完成的请求,如果存在会将请求对象作为事件处理,这也就是上面说的事件的由来。通读之后是不是有种豁然开朗的感觉。还有如果一点callback函数的trigger是在I/O观察者的回掉方法中执行(每个事件循环都会有至少一个的观察者),取出之前咱们添加到请求对象属性上的方法进行调用。

5. Node构建Web服务器的执行流程是什么样的?

    其实如果你对上面都已经理解基本上也就知道了大概的执行流程,下面的图给出一个参考。

Nodejs基础知识整理_第3张图片

6. NPM与包。

    包和NPM是将模块之间联系起来的一种机制。如下图。CommonJS包规范定义中包含两点包结构和包描述文件。

    Nodejs基础知识整理_第4张图片

      · 包结构

package.json 包描述文件
bin 用于存放可执行二进制文件的目录
lib 用于存放JavaScript代码的目录
doc 用于存放文档的目录
test 用于存放单元测试用例的代码

    · 包描述文件与NPM

              创建一个packgage.json文件可以手动创建与根目录下,或者用npm init命令,根据提示填写。

name 包名
description 包简介
version 版本号
keywords 关键词数组
maintainers 包维护者 example=> “maintainers”: [{"name": "Jackson Tian", "email": "[email protected]", "web": "http://html5ify.com"}]
contributors 贡献者列表
bugs 一个可以反馈bug的网页地址或者邮箱地址
licenses 当前包所使用的许可证列表 example=> "licenses": [{"type": "GPLv2", "url": "http://www.example/licenses/gpl.html"}]
repositories 托管源代码的位置列表
dependencies 当前包所需要的依赖包列表
homepage 当前包的网站地址
os 操作系统
cpu CPU架构的支持列表
engine 支持的JavaScript引擎列表
builtin 标志当前包是否是内建在底层系统的标准组建
directories 包目录说明
scripts 脚本说明对象
author 包作者
bin 一些包作者希望包可以作为命令行工具使用
main 模块引入方法require()在引入包时会优先检查这个字段,并将其作为包中其余模块的入口,如果不存在这个字段,require()方法会自动查找包目录下的index.js,index.node,index.json文件作为默认入口

                                   对于Node而言NPM基于以上规范解决依赖包的安装问题,同时帮助完成了第三方模块的发布,安装和依                              赖等。借助NPM,Node与第三方模块之间形成了很好的生态系统。

               · NPM常用命令

                          npm -v  查看版本号

                         npm install express  NPM会在当前目录下创建node_modules目录,然后在node_modules目录下创建express目录,然后把包解压到这个目录下。

                         npm install express -g  进行全局安装,并不是从任何地方都可以通过require()引用到它,而是需要通过软连接的方式链接到Node的可执行目录下。也就是需要在package.json的bin字段下进行配置。

                         npm install 当网络不好的时候可以把包download到本地,然后从本地进行安装。

                         npm install --registry=http://registry.url 使用镜像进行安装,如淘宝镜像需要把镜像地址替换成淘宝镜像。

                         npm config set registry http://registry.url 设置淘宝镜像。

                         npm uninstall 包卸载

                         npm test 运行测试用例,一个优秀的包中应该包含测试用例,以便检查包是否稳定可靠。

                         npm adduser 发布包时的前提,你得注册了仓库管理账号。如果你还没有仓库账号就去仓库传送门吧。

                         npm publish 开发发布。

                         npm owner ls 查看包拥有者

                         npm owner add 添加拥有者

                         npm owner rm 删除一个拥有者

                         npm ls 分析包,列出可以通过require()引入的所有包,并生成依赖树。

 

至此,Node比较基础的概念和原理就先介绍到这,以上为个人理解,不到之处望海涵与指正。

你可能感兴趣的:(NodeJS)