刚刚开始接触Node.js时, google了很多文章,但发现大部分都是泛泛的介绍安装,配置,以及介绍几个小例子

有一种雾里观花的感觉,所以非常困惑,不知道Node.js到底解决了什么问题,它的优势到底在哪儿,为什么这么火。

经过了一番学习之后, 自认为对Node.js的基本原理有了些了解, 于是杜撰了下面这个故事,希望对大家有所帮助,能给大家一点启发

美丽的七侠镇上有一条美食街,很多著名的饭店都开在这里,有老字号的Apache, PHP, 最近几年火热的Ruby on Rail ,
还有那些重量级的餐饮集团Websphere, Weblogic 等。

这些饭店老板根据自己的实力,或多或少的雇佣了一些店小二来招待来客,这些小二干活都非常殷勤,没有一个偷懒耍滑,把顾客招待的舒舒服服, 所以平日里饭馆运转的还不错,相安无事。

但是随着七侠镇旅游业开发,游客像潮水一样蜂拥而至, 现有的店小二招待不过来了, 到了饭点,每家的门前都排起了长队,游客们吃不上饭,个个怨声载道。

看到这种情况,有些老板咬了咬牙,在人工费不断上涨的情况下, 多雇了一些小二来帮忙, 无奈总是赶不上顾客增长的速度。

某一天有个美国老外来到七侠镇上旅游, 也看到了吃不上饭的问题,他仔细分析了一番后发现了一个秘密: 原来这些店都采用了同一套叫做“全程贴心服务”的模式, 这个模式很有意思:

客人来了以后,马上有个店小二殷勤迎上去,带着找座位,点菜,给后厨下单

由于后厨做菜需要很长时间,店小二就在客人的旁边等着。

后厨大喊一声:上菜,店小二马上端到客人面前, 然后站在一边等着客人吃完

客人说:结账,小二收钱,找钱,送客, 迎接下一位。

通常这个时候门口都排成了好几百人了

实在是太贴心了! 导致的结果很明显,饭店有几个店小二,就只能同时接待几个顾客。

(当然,现实中是没有饭店是这么做的,否则就等着关门吧)

老外一声不吭的回去了。

过了几个月, 美食一条街上出现了一个巨火无比的饭馆: Node.js

虽然这个饭店中人满为患, 可门口竟然没有排队的

更让人吃惊的是,这个店里声称: 我只需要一个店小二!

Node.js这个美国老外开的饭店确实只用了一个店小二, 只不过这个小二干活的方式与众不同,他把所有的工作分为两类

(1) 马上就能干完的,例如迎客,点菜,找座,下单 等等

(2) 需要等待别人干完才能干的活,例如上菜,结账等

对(1) 这个小二马上干活

对(2) 店小二不会等待,他只是说,你弄完了告诉我一声,我会接着干, 然后马上去做第一类工作

客人来了以后,这个店小二殷勤迎上去,带着找座位,点菜,给后厨下单

由于后厨做菜需要很长时间,店小二闪电般的离开,去干别的活了,可能是迎客,点菜,找座等,总之是那些不用等待,迅速干完的活

后厨大喊一声:上菜,这个小二马上端到客人面前,然后离开,干其他活

客人说:结账,小二收钱,找钱,然后还是迅速闪人,干其他活

这个唯一的店小二的能力被发挥到了极致,一刻不停,闪电般的在饭店里跑来跑去,因为老板明确的告诉他: 不要等!

Node.js饭店的基础设施很强大,一旦那些耗时的操作完成,店小二立刻就能知道,飞奔过来马上接着干,如果遇到新的耗时的操作,小二毫不留情的离开。

就这么简单, Node.js饭店火了,它同时接待客人的数量大大增加,而服务质量保持基本不变。

OK,这是我杜撰出来的一个不成熟的故事,帮助我来理解Node.js的特点:只用一个线程来处理所有请求,事件驱动编程

如果我们回过头来再以计算机的视角看一下会更加清楚:

店小二: 线程

顾客:http请求

第一类工作(迎客,找座,下单) : 在服务器端的代码,能够快速执行

后厨做菜,客人吃饭: 耗时的I/O 操作

后厨大喊一声:上菜 : 这是一个长时间I/O 操作完成的后所发出的事件

客人说:结账: 另外一个长时间I/O 操作完成的后所发出的事件

第二类工作(上菜,结账) : 同样是能快速执行的代码,但是他们需要等待那些耗时的I/O 操作完成才能开始,确切的来说,收到了系统发出的事件以后才开始执行。在Node.js中实际上是在回调函数中来执行的

下面是Node.js服务模式的伪代码:

  1. 迎客();
  2. 找座();
  3. 下单();
  4. 后厨处理("做菜完成事件", function(){
  5. 上菜处理;
  6. 客人吃饭("吃饭完成事件",function(){
  7. 结账处理;
  8. 送客();
  9. });
  10. });

需要引起注意的是:

1. 后厨处理()这个函数接受两个参数,一个是事件名,另外一个是匿名的回调函数,事件发生,回调函数才会执行。

客人吃饭()函数也是类似。

Node.js 使用的javascript作为服务器端的编程语言,这种回调的方式对于javascript程序员来说,是非常自然的事情,同时从代码的角度来讲,也显得非常清晰。

另外Node.js使用Chrome的V8引擎来执行javascript,效率非常高

2. 我们能不能把代码写成这样?

  1. 迎客();
  2. 找座();
  3. 下单();
  4. 后厨处理("做菜完成事件", function(){
  5. 上菜处理;
  6. });
  7. 客人吃饭("吃饭完成事件",function(){
  8. 结账处理;
  9. });
  10. 送客();

肯定不行!, 因为Node.js执行"后厨处理()"函数时,只是安插了一个匿名的回调函数在那里,并不会等待(非阻塞I/O),反而马上 会执行“客人吃饭()"函数,所以上述的写法会引起逻辑上的错误:还没上次就开始吃饭了!

所以写惯了”顺序阻塞I/O“的我们需要改变一下思维方式,进入到事件驱动的世界中来。

3. 如果某个操作例如“上菜处理” 是个CPU密集型的计算任务,Node.js那个唯一的线程就会忙于执行这个计算任务而被Block 住,就无法响应其他的请求了,带来的后果很严重,整个服务器都无法响应了!  这个时候,需要考虑把这样的代码进行异步处理

这里我只是粗浅的讨论了Node.js的原理, 哪位同学要想亲自动手试一试的话,这里是一篇非常好的Node入门文章:Node入门

另外还有两篇深入介绍的文章,非常值得一读(虽然是英文的)

理解Node.js 事件循环

理解Node.js

后记: 第一次看到Node.js, 确实挺吃惊的, 把javascript 作为服务器端的编程语言,只用一个线程来处理所有请求!

它的作者Ryan Dahl 确实敢想敢干, 再一次体现了美国人的创新精神,非常值得我们学习。

中国的程序员也需要反思一下,我们为什么没有想到? 我们为什么没有做出来?

Node.js : 我只需要一个店小二的更多相关文章

  1. 前端使用node.js的http-server开启一个本地服务器

    前端使用node.js的http-server开启一个本地服务器 在写前端页面中,经常会在浏览器运行HTML页面,从本地文件夹中直接打开的一般都是file协议,当代码中存在http或https的链接时 ...

  2. npm 是node.js下带的一个包管理工具

    npm 是node.js下带的一个包管理工具          npm install -g webpack webpack是一个打包工具 gulp是一个基于流的构建工具,相对其他构件工具来说,更简洁 ...

  3. 用node.js从零开始去写一个简单的爬虫

    如果你不会Python语言,正好又是一个node.js小白,看完这篇文章之后,一定会觉得受益匪浅,感受到自己又新get到了一门技能,如何用node.js从零开始去写一个简单的爬虫,十分钟时间就能搞定, ...

  4. 使用node.js的http-server开启一个本地服务器

    用html写了一个网页,想要在手机上查看适配效果,但是苦于手机上没有直接查看HTML的.想到手机和电脑都在一个局域网内,能不能搭建一个局域网内的网页服务器呢? 1.下载 http-server 显然, ...

  5. 使用Node.js原生API写一个web服务器

    Node.js是JavaScript基础上发展起来的语言,所以前端开发者应该天生就会一点.一般我们会用它来做CLI工具或者Web服务器,做Web服务器也有很多成熟的框架,比如Express和Koa.但 ...

  6. Node.js入门以及第一个helloworld程序

    1.概念:简单的说 Node.js 就是运行在服务端的 JavaScript.学之前需要明白Node.js是无法挑战jsp.php或者asp这种老牌网站的地位的,是永远不会出现在证券.金融这种领域的. ...

  7. Node.js 被分叉出一个项目 — Ayo.js,肿么了

    (注:ayo.js叉从Node.js.目前,大量的文档仍然指向Node.js库.) ayo.js是一个JavaScript运行时建立在Chrome的V8 JavaScript引擎.ayo.js使用事件 ...

  8. Node.js -- Router模块中有一个param方法

    这段时间一直有在看Express框架的API,最近刚看到Router,以下是我认为需要注意的地方: Router模块中有一个param方法,刚开始看得有点模糊,官网大概是这么描述的: 1 Map lo ...

  9. 【Node.js】4.从一个例子切入Node js的规范

    在开始之前,需要明确的一点就是, ①Node应用是由模块组成的,每一个文件都是一个模块,有自己的作用域. ②在这个文件里定义的变量,函数,类都是私有的,对其他的文件不可见. ③在一个文件中,也就是在一 ...

随机推荐

  1. 与众不同 windows phone (21) - Device(设备)之摄像头(拍摄照片, 录制视频)

    原文:与众不同 windows phone (21) - Device(设备)之摄像头(拍摄照片, 录制视频) [索引页][源码下载] 与众不同 windows phone (21) - Device ...

  2. 2cifang.com_2次方学习

    2cifang.com_2次方学习

  3. VC调试篇

    难怪很多前辈说调试是一个程序员最基本的技能,其重要性甚至超过学习一门语言.不会调试的程序员就意味着他即使会一门语言,却不能编制出任何好的软件. 我以前接触的程序大多是有比较成形的思路和方法,调试起来出 ...

  4. 关于__stdcall和__cdecl调用方式的理解

    __stdcall和__cdecl都是函数调用约定关键字,先给出这两者的区别,然后举实例分析: __stdcall:参数由右向左压入堆栈:堆栈由函数本身清理. __cdecl:参数也是由右向左压入堆栈 ...

  5. C++经典笔试题及参考答案-趋势科技

    1.static有什么用途?(请至少说明两种) 答案:1)在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变. 2)在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数 ...

  6. Java网络编程-对象编解码方案、优劣对照

    书籍推荐:   实例代码 :http://download.csdn.net/detail/jiangtao_st/7677503 watermark/2/text/aHR0cDovL2Jsb2cuY ...

  7. maven使用.02.一些概念

    在上一篇POST中,简要的介绍了一下maven的特点,优势,安装.并建立了一个简单地Hello world工程.这一篇POST中,将主要会介绍一下Maven的一些约定. pom.xml文件 Maven ...

  8. Oracle定时执行存储过程(转)

    定时执行存储过程在平时开发中经常会用到,年前的时候自己也做了一个,由于时间关系一直没能记录,现记录下来.       首先用一个完整的例子来实现定时执行存储过程. 任务目标:每小时向test表中插入一 ...

  9. UVAlive 2519 Radar Installation (区间选点问题)

    Assume the coasting is an infinite straight line. Land is in one side of coasting, sea in the other. ...

  10. NET实现的DDD、CQRS与微服务架构

    WeText项目:一个基于.NET实现的DDD.CQRS与微服务架构的演示案例 最近出于工作需要,了解了一下微服务架构(Microservice Architecture,MSA).我经过两周业余时间 ...