Node.js从入门到精通 Node.js应用实战和工作原理解析
沉沙 2018-06-06 来源 : 阅读 1122 评论 0

摘要:Node.js是一个基于Chrome JavaScript运行时建立的开发平台, 用于方便地搭建响应速度快、易于扩展的网络应用。Node.js 使用事件驱动,非阻塞I/O模型而得以轻量和高效,非常适合在分布式设备上运行数据密集型的实时应用,例如移动应用里的消息模块。

    Node.js是一个基于Chrome JavaScript运行时建立的开发平台, 用于方便地搭建响应速度快、易于扩展的网络应用。Node.js 使用事件驱动,非阻塞I/O模型而得以轻量和高效,非常适合在分布式设备上运行数据密集型的实时应用,例如移动应用里的消息模块。

    本文分为俩个部分:

    第一部分:通过应用层面,给大家演示什么Node.js,它能做什么,怎么去做。

    第二部分:在大家对Node.js有个基本认识之后,从理论层面谈谈Node.js的运行机制。

    Node.js应用解析

    Node.js是能够跨平台的,今晚我们分享将基于windows,但linux或者macro大致相同。

    nodejs环境搭建

    首先登陆node官网下载安装包,地址是:nodejs.org/en/

    下载完成之后,安装步骤就是傻瓜式的下一步下一步:

    安装完成之后在windows下打开powershell,然后执行 " node -v "就能查看到我们node的版本信息,这也就说明我们的node已经安装成功。

    第一个demo

    之后我们找个目录新建一个项目文件夹,然后在项目文件夹下面新建一个hello__.js的文件,将如下代码写入hello__.js的文件:

    而后我们cd到项目目录下,运行node hello__.js

    然后在浏览器里输入127.0.0.1:8899就能直接访问我们的服务了

    我们在代码中用了 var http = require("http"); 这种方式引用了node的一个自身模块http,模块可以理解成DotNet的类库、Java的包,然后应用这个http模块快速建了一个服务,这也是node给开发人员带来的便利。

    NPM

    说到便利,对于node.js还必须要提到NPM,在上个demo中我们用到var http = require("http"); 来引用模块,我们也说到了http是node自身的模块,那么如果需要引用一些node的非自身模块,应该如何做呢?

    这个任务的第一步就交给NPM,在安装node的同时已经将NPM工具安装完成,我们只需要执行NPM -v就能查看NPM的版本,直接输入NPM可以查看相关帮助。

    NPM的最常见用法就是安装依赖模块,当安装完成之后我们的项目就能对安装的依赖模块进行引用。现在我们拿 express模块来举个栗子,首先需要cd 到项目的node_modules目录下,然后运行npm install express:

    当你看到这样的界面的时候就说明模块已经安装成功,回到项目目录下就能看见模块目录下新增了一个express目录,然后在项目目录下创建一个hello.js的脚本文件,文件内容如下:

    下一步就是启动这个项目,直接运行 node .\hello.js

    然后在浏览器里输入地址127.0.0.1:8081

    这种方式引用模块非常方便。那么我们是不是也可以编写自己的第三方模块上传到npm库给他人使用呢?答案是肯定的!接下再举个栗子给大家说明下,首先在项目根目录下创建一个npmtest文件夹:

    在当前目录下创建一个hello.js文件,内容如下:

    然后运行npm init 命令,在运行命令之后会要求你输入一些模块打包的描述信息,这些信息最终会生成一个包的描述文件叫package.json

    输入所有信息之后会问你"Is this ok?",输入yes就完成了打包过程。查看文件夹下面会增加一个描述包文件:

    然后大家再look下我们生成描述文件的内容:

    可以看到这些信息都是刚才输入的内容。包打好了,接下来就是上传到仓库,上传仓库前我们先注册一个账号npm adduser,然后输入用户名、密码还有邮箱地址就可以了。

    现在万事具备了,东风来吧,运行npm publish ,就可以把我们包上传了:

    注意publish后面有一个点 ”.“。当我们的包上传完成之后,通过调用来做个验证,换个目录下来执行 npm install cloudwise_else_npmtest:

    在我们的目录里查看,就知道创建的模块已经引用过来了:

    上面我们介绍Node.js的环境搭建,模块安装、引用,以及如何创建和引用自己的模块,并对每一个点都做了相应的示例。

    调试工具

    现在我们已经能够让项目run起来了,项目运行过程中如果出现异常怎么办,这是程序猿尤为关心的。在我接触的PHP开发者中,他们比较习惯用日志去跟踪,本人是DotNet的忠实粉丝,江湖流传宇宙最强IDE的Visual Studio给DotNet开发者提供了非常强大的调试功能,可以让我们随心所欲的调试,快速准确的定位到Bug。所以日志调试让我很不能接受,如此火热的Node.js肯定也给开发者提供了不错的debug工具。

    首先还是用npm来安装,命令如下:

    npm install -g node-inspector

    启动的时候我们会在中间加一个debug,命令如下:

    node debug .\hello.js

    接下来我们启动调试插件 node-inspector.cmd,此处linux跟windows有点差别,linux下没有后面cmd,然后打开浏览器(当前此插件只支持chrome跟Opera),地址如下://127.0.0.1:8080/?port=5858

    当我们在代码中打断点的时候,程序就会捕获到断点,然后在这里添加监视,也可以单步执行或者逐过程逐语句,爱怎么玩就怎么玩。说到这里我们对Node.js是什么、能做什么、怎么做有了基本的认识,那么是不是就可以开始coding工作了呢?

    完全可以的!有人或许会问,Node.js能做的事情php、java、.net也都能做,为什么要选择Node.js呢,难道单单是因为他不用去搭建Apache、IIS、Tomcat吗?接下来我就根据自己的理解和大家探讨下Node.js能够在最近几年被聚光的缘由。

    Node.js运行机制解析

    当我们搜索Node.js时,夺眶而出的关键字就是 "单线程,异步I/O,事件驱动",应用程序的请求过程可以分为俩个部分:CPU运算和I/O读写,CPU计算速度通常远高于磁盘读写速度,这就导致CPU运算已经完成,但是不得不等待磁盘I/O任务完成之后再继续接下来的业务。

    所以I/O才是应用程序的瓶颈所在,在I/O密集型业务中,假设请求需要100ms来完成,其中99ms化在I/O上。如果需要优化应用程序,让他能同时处理更多的请求,我们会采用多线程,同时开启100个、1000个线程来提高我们请求处理,当然这也是一种可观的方案。

    但是由于一个CPU核心在一个时刻只能做一件事情,操作系统只能通过将CPU切分为时间片的方法,让线程可以较为均匀的使用CPU资源。但操作系统在内核切换线程的同时也要切换线程的上线文,当线程数量过多时,时间将会被消耗在上下文切换中。所以在大并发时,多线程结构还是无法做到强大的伸缩性。

    那么是否可以另辟蹊径呢?!我们先来看看单线程,《深入浅出Node》一书提到 "单线程的最大好处,是不用像多线程编程那样处处在意状态的同步问题,这里没有死锁的存在,也没有线程上下文切换所带来的性能上的开销",那么一个线程一次只能处理一个请求岂不是无稽之谈,先让我们看张图:

    Node.js的单线程并不是真正的单线程,只是开启了单个线程进行业务处理(cpu的运算),同时开启了其他线程专门处理I/O。当一个指令到达主线程,主线程发现有I/O之后,直接把这个事件传给I/O线程,不会等待I/O结束后,再去处理下面的业务,而是拿到一个状态后立即往下走,这就是“单线程”、“异步I/O”。

    I/O操作完之后呢?Node.js的I/O 处理完之后会有一个回调事件,这个事件会放在一个事件处理队列里头,在进程启动时node会创建一个类似于While(true)的循环,它的每一次轮询都会去查看是否有事件需要处理,是否有事件关联的回调函数需要处理,如果有就处理,然后加入下一个轮询,如果没有就退出进程,这就是所谓的“事件驱动”。

    本了解了异步I/O、单线程、事件驱动这几个Node的标签,这里再引入一个观察者的概念,每次轮询都会去向观察者询问是否有事件需要处理,这个过程就如同饭馆的后厨,厨房一轮一轮的制作菜肴,具体做什么菜取决于餐厅里客人的下单,厨房做完成就询问收银小妹接下来做什么菜,而收银小妹就是观察者,他收到的客人点单就是关联的回调函数,如果生意好的饭馆会有多个收银小妹,就如同事件循环中有多个观察者,收到下单就是一个事件,一个观察者里头可能有多个事件。

    在node.js中,事件主要来源于网络请求,文件I/O等,根据事件的不同对观察者进行了分类,有文件I/O观察者,网络I/O观察者。事件驱动是一个典型的生产者/消费者模型,请求到达观察者那里,事件循环从观察者进行消费,主线程就可以马不停蹄的只关注业务不用再去进行I/O等待。

    那么您可能会问,这种单个线程进行运算,对于多核CPU的服务器岂不是英雄无用武之地,还有就是当主线程业务运算超时,岂不是来不及处理事件队列里(观察者里头)的事件?

    对于这俩个问题,首先要做的一点就是在代码编写的时候尽量避免耗时的计算,将大计算进行拆分,这样能够让主线程及时得到释放,处理消费事件队列里头的事件。其次,node.js提供了child_process模块开启子进程,理想状态下每个进程各自利用一个CPU,以此实现多核的利用,child_precess提供创建子进程,以及进程状态监控,进程之间通信的API,感兴趣的小伙伴可以问问度娘,或者欢迎私聊。

    聊到这里,我们就可以回顾前面的问题,为什么在有PHP、Java、DotNet的今天我们还会去选择Node.js,因为它的单线程、异步I/O、事件驱动特点能够更好的处理I/O密集型的业务场景,同时它在多核CPU利用上面也做的非常优秀,这就是他存在的理由!

    当然,如果你的业务场景几乎没有任何I/O操作,属于纯CPU密集型的业务,那最好还是选择一种多线程语言。

    本文由职坐标整理发布,欢迎关注职坐标Node.js频道,学习更多WEB前端知识!


本文由 @沉沙 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程