【Node.js】一篇文章带你彻底理解Node.js及其特性

什么是Node.js

简单的说,Node.js就是运行在服务端的JavaScript,它打破了JavaScript只能在浏览器运行的局面,并且让JavaScript的生态建设走向正轨。

Node.js最初的开发者,是想要写一个基于事件驱动的、非阻塞I/O的Web服务器,提供ApacheTomcat之外的选择。其实,我们完全将Node.js看作是一个极其轻量的Web服务器

Node.js不是开发者无中生有得来的,当我们把Chrome和Node的架构图摆在一起时,不难发现它们有着惊人的相似之处——尤其是那个无比卓越的执行引擎,V8。

 
 

特点特性

1)异步I/O

并发已经是编程的标配,因为串行执行的效率实在太低。但我们知道,JavaScript是单线程的。

这是JS的用途决定的:交互,就是操作DOM。如果是多线程的,那么难免会出现一个线程还在操作DOM,而另一个线程却删掉DOM的危险情况。

Node在两者之间给出了它的方案:利用单线程,远离线程死锁、状态同步等问题;利用异步I/O,解决单线程阻塞的问题,提升性能。

2)事件驱动

事件的编程方式具有轻量级、松耦合、只关注事务点等优势,但是在多个异步任务的场景下,事件与事件之间各自独立,如何协作是一个问题。

3)回调函数

纵观下来,回调函数也是最好的接受异步调用返回数据的方式。

但是这种编程方式对于很多习惯同步思路编程的人来说,也许是十分不习惯的。代码的编写顺序与执行顺序并无关系,这对他们可能造成阅读上的障碍。在流程控制方面,因为穿插了异步方法和回调函数,与常规的同步方式相比,变得不那么一目了然了。

异步I/O、事件驱动、回调函数,这些不都是JavaScript的特性吗?
没错,Node.js没有改变语言本身的任何特性,且依旧基于作用域和原型链,区别在于它将前端中广泛运用的思想,迁移到了服务器端而已。
因此,这部分的内容完全可以结合JavaScript本身的【执行栈-任务队列–事件循环机制】进行理解。

 
 

应用场景

在技术选型时,什么技术适合什么场景十分重要。下面,对于Node.js,我们探讨一下它在I/O密集型和CPU密集型两种场景的表现。

I/O密集型

如果把所有的脚本语言叫到一起,并预设单线程的前提条件,那么Node处理I/O的能力绝对会脱颖而出。我们通常这么说:Node擅长I/O密集型的应用场景。

这是因为Node利用了loop循环和事件驱动。而不是为每一个请求开启一个线程,一直占用着。

下面结合计算机组成原理的知识说一下非阻塞。当处理机上是一个I/O任务时,会发生阻塞(处理机主动的行为),由运行态切换为阻塞态。而Node.js的非阻塞特性就是说,当前线程(反正只有一个)不会下处理机,I/O任务被放到任务队列中,等会儿再去执行。

CPU密集型

Node足以胜任有大量计算需求的CPU密集型场景。为什么呢?还是因为那至今仍变态的V8执行引擎。单单从计算的执行效率上看,Node表现非常不错。

但问题在于,JavaScript是单线程的。对于一些大型的计算,会占用大量的时间片,阻塞了后续的I/O任务的发起。通俗地说,一个长度为10的线程(前9个是计算任务,后1个是I/O任务),前9个计算任务完成了,才轮到最后1个I/O任务,这就导致这个I/O任务的响应时间特别长。

如何解决?如果JavaScript是多线程的,那么我们把计算任务和I/O任务放到两个线程上就好了,通过CPU调度,I/O也能相对公平的上CPU,但我们无法这么做。其实,我们还可以把这个大的计算任务,分解为多个小计算任务,从而在可接受时间内完成计算并释放CPU。

 
 

彻底理解Node.js

下面的内容原创于国外的一篇文章(文末附网址),把node.js、非阻塞、事件驱动、长轮询等概念用人话讲了出来,循序渐进、通俗易懂。网上有已有翻译版本,我对其进行了更加简略的翻译,希望能让大家读的更加明明白白。

你一定不止一次听说过Node.js,你或许会问:“What is it?”。

有些人会告诉你,这是一种用JavaScript语言写服务端的方式。如果你没有被这种晦涩的解释吓走,或许会接着问:为什么要使用它?他们又会这样回答:Node.js的优点是非阻塞(non-blockin)、事件驱动(event-driven)、长轮询(long polling)

这时你可能已经放弃,闭嘴不问了。这不怪你,这篇文章就是要避开这些术语,通俗来向你解释这一切。

B/S模型没怎么变过——用户从浏览器发出请求,服务器收到请求后,开始去找对应的资源;如果有需要,还会去查一下数据库;最后,把响应结果传回浏览器。在传统的web服务器中(比如ApacheTomcat),每一个HTTP请求都会让服务器创建一个新的线程。

随着Ajax技术的兴起,用户与服务器之间的长轮询技术出现了。我们知道,普通的请求就是浏览器发出一次、服务器响应一次就结束了——这不是一个连续的过程,但我们可以通过小技巧来模拟出一个看似连续的状态,就像上面那种时刻保持的连接一样。具体的实现是,就算现在无事可做,你依旧要发给服务器一个Ajax请求。这个Ajax请求不同与一般的请求,它并不要求服务器立即做出响应,而是可以hold住,等到服务器想要响应了再响应。当服务器给出的响应返回后,你在此发送一个这样的Ajax请求,如此反复。这样,就用一个个不连续Ajax请求,模拟出了持续连接的状态——这就是长轮询

我们想象这样一个需求。你建立了一个类似微信朋友圈功能的社交网站,你的朋友们会把新鲜事分享出来,这时你的朋友圈界面要实时刷新这些新鲜事。要达成这个需求,需要让用户一直与服务器保持一个有效的连接。如果是传统的ApacheTomcat服务器,一个用户就要占用这样一个进程,那你的服务器早就爆炸了。

如何解决这种场景?非阻塞事件驱动。你可以把非阻塞的服务器想象成一个Loop环,这个Loop环会一直跑下去。当有一个事件发生,触发了一个请求,Loop环接受了这个请求并从环主体上脱离出一个回调(callback)来处理这个请求,Loop环依旧在跑。如果更严谨的说,回调函数的第一阶段会占用环的时间(去查数据库的动作),但回调函数的第二阶段已经与环脱离(回调函数自己会等待数据库查询结果,并将其作为响应返回)。

上面这两段话可以看图理解。在这里插入图片描述

像Tornado框架、nginx服务器都是按上面的原理工作的,但Node.js就更妙了——Node.js将JavaScript作为实现语言,而JavaScript本身就天天在搞回调、本身就是事件驱动的脚本语言。用事件驱动的语言去搭建事件驱动的服务器端,用四个字可以形容:天作之合

 

—— —— 翻译自https://www.sitepoint.com/node-js-is-the-new-black,有删减和改编

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

JS Saikou!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值