深入了解Node.js中的一些特性


Posted in Javascript onSeptember 25, 2014

Node.js作为一门新兴的后台语言,旨在帮助程序员快速构建可伸缩的应用程序。Node.js有很多吸引人的地方,有关它的报道不计其数,本文将针对EventEmitter、Streams、Coding Style、Linting、Coding Style等特性进行分析探讨,帮助用户对Node.js有更深入的了解。

作为一个基于Chrome JavaScript 运行时建立的平台,我们对JavaScript 的相关认识,似乎都可应用于node应用程序之上;无需额外的语言扩展或修饰,我们便可以把前端编程的经验应用于后端编程。

EventEmitter(事件发送器)

首先应该先了解EventEmitter模型。它可以发送一个事件以及让消费者订阅感兴趣的事件。我们可以把它看成是向一个异步函数进行回调传递模式的扩展。特别是,当需要进行多次回调时,EventEmitter会更显优势。

例如,有一个调用者向远程服务器发送了一个“列出文件”的请求。你可能想对返回结果进行分组,对每一个分组进行一次回调处理。EventEmitter模型可以让你在每一个分组上发送“文件”回调,当全部操作完成时进行“结束”处理。

使用EventEmitter时,只需设置好相关事件和参数。

var EventEmitter = require('events').EventEmitter;  

var util = require('util');  

  

function MyClass() {  

  if (!(this instanceof MyClass)) return new MyClass();  

  

  EventEmitter.call(this);  

  

  var self = this;  

  setTimeout(function timeoutCb() {  

    self.emit('myEvent', 'hello world', 42);  

  }, 1000);  

}  

util.inherits(MyClass, EventEmitter); 

MyClass构造函数创建了一个时间触发器,触发延时为1s,触发事件为myEvent。要使用相关事件,需要执行on()方法:

var myObj = new MyClass();  

var start = Date.now();  

myObj.on('myEvent', function myEventCb(str, num) {  

  console.log('myEvent triggered', str, num, Date.now() - start);  

}); 

这里要注意的是,订阅的EventEmitter事件虽然是异步事件,但当时间触发时,监听方的动作是会同步的。因此如果上述myEvent事件有10个监听者,所有的监听会被按次序调用而不用等候事件的循环。

如果EventEmitter的一个子类生成了一个emit(‘error')事件,但是无任何的监听方对此进行订阅,那么EventEmitter基类会抛出一个异常,从而导致当执行process对象时触发uncaughtException事件。

verror

verror是基类Error的扩展,可以让我们使用printf字符格式定义输出消息。

Streams(流)

如果有一个非常庞大的文件需要处理,理想的方法应该是读一部分,写一部分,不管文件有多大,只要时间允许,总会处理完成,这里就需要用到流的概念。Streams是Node中另一个广泛使用的模型,在Node中是EventEmitter的实现。提供了可读、可写或者是全双工接口。它是一个抽象接口,提供的常规操作事件包括:readable、writable、 drain、data、 end及close。如果我们能够使用pipeline(管道)来对这些事件进行有效整合,将可实现功能更强大的交互操作。

透过使用.pipe(),可以让Note通过pipeline与back-pressure进行通信。back-pressure的意思是:只读取那些能够写入的,或只写入那些能够读取的。

例如我们现在把来自stdin的数据发送到一个本地文件和远程服务器:

var fs = require('fs');

var net = require('net');
var localFile = fs.createWriteStream('localFile.tmp');
net.connect('255.255.255.255', 12345, function(client) {

  process.stdin.pipe(client);

  process.stdin.pipe(localFile);

});

而如果我们想发送数据到一个本地文件,并想使用gunzip对这个stream进行压缩,可以这样做:

var fs = require('fs');

var zlib = require('zlib');
process.stdin.pipe(zlib.createGunzip()).pipe(fs.createWriteStream('localFile.tar'));

如果想对stream有更多了解,请点击这里。

Control Flow(流程控制)

由于JS中有第一类对象,闭包等功能概念,因而能够容易地对回调权限进行定义。这在进行原型设计时是非常方便的,能够对逻辑权限按需进行整合。但是同时容易造成使用笨拙的内置函数。

例如我们想按次序读入一系列文件,然后执行某个任务:

fs.readFile('firstFile', 'utf8', function firstCb(err, firstFile) {

  doSomething(firstFile);

  fs.readFile('secondFile', 'utf8', function secondCb(err, secondFile) {

    doSomething(secondFile);

    fs.readFile('thirdFile', 'utf8', function thirdCb(err, thirdFile) {

      doSomething(thirdFile);

    });

  });

});

这个模式存在的问题是:

1.这些代码的逻辑非常散乱无序,相关的操作流程难以理解。
2.没有任何差错或异常处理。
3.JS中闭包内存泄漏是非常常见的,并难以诊断和探测。

如果我们想在一个输入集上进行一系列异步操作,使用一个流程控制库是更明智的选择。这里使用的是vasync。

vasync是一个流程控制库,其思路来源于异步操作。它的特别之处是能够让消费者对某个任务处理过程进行查看和观察。这些信息对研究某个错误的产生过程是非常有用的。

Coding Style(编程风格)

编程风格可谓最具争议性的话题,因为很多时候都是随性的。萝卜白菜,各有所爱。重要的是找到适合个人和团队的风格。一些传统的传承或许能够让Node开发之旅变得更美好。

1.为函数命名
2.尽量对所有函数进行命名。
3.避免闭包
4.不要在某个函数中定义其它函数。这可减少很多想不到的闭包内存泄露意外。
5.更多和更小巧的函数

V8 JIT虽然是一个功能强大的引擎,但是更小巧和精简的函数会与V8结合得更好。进一步说,如果我们的函数都是小巧玲珑的(100行左右),我们自己进行阅读和维护时也会感谢自己的。

用编程方式检查风格:保持风格一致性,并使用一个检查工具来加强。我们使用的是jsstyle。

Linting(代码检查)

Lint工具可以在不运行情况下进行代码的静态分析,检查出潜在的错误和风险,例如在caseswitch中遗漏了break语句。Lint不简单地等同于风格检查,它更针对于客观的风险分析,而不是主观的风格选择。我们使用的javascriptlint,它里面有丰富检查项目。

Logging(日志记录)

当我们进行程序设计和编码时,需要有长远的目光。特别是要考虑好使用什么工具来进行调试。极好的第一步是进行有效日志记录。我们需要对信息进行识别,看看什么是调试时特别留意的,什么是运行时用来分析研究的。这里推荐使用Bunyan,一个直接的Node.js日志记录库,数据输出格式是JSON ,要了解更多信息,请点击这里。

Client Server

如果一款应用具备分布式处理能力,在市场上会更有吸引力。类似的接口可以用HTTP RESTFul API或原始的TCP JSON来描述。这可以让开发者把Node上的经验与异步网络环境相结合,以及把streams的使用与分布式可扩展式系统相结合。

常用工具:

1. restify

简单来说,这是一个用于构建REST服务的工具。它提供了良好的查看和调试处理支援,同时支持Bunyan与DTrace。

2. fast

fast是一款以TCP来处理JSON消息的轻量级工具。提供了DTrace支持,能够让我们迅速地对服务器客户端进行性能特征识别。

3. workflow

workflow构建于restify之上,能够对一系列远程服务和API进行业务流程定义。例如:错误状态,超时,重新连接,拥塞处理等。

Javascript 相关文章推荐
jQuery实现的多选框多级联动插件
May 02 Javascript
原生js和jQuery随意改变div属性style的名称和值
Oct 22 Javascript
jQuery实现表格行上移下移和置顶的方法
May 22 Javascript
最佳的JavaScript错误处理实践
Jul 16 Javascript
详解Angular.js指令中scope类型的几种特殊情况
Feb 21 Javascript
Angular4项目中添加i18n国际化插件ngx-translate的步骤详解
Jul 02 Javascript
浅谈mint-ui loadmore组件注意的问题
Nov 08 Javascript
vue自定v-model实现表单数据双向绑定问题
Sep 03 Javascript
微信小程序使用canvas自适应屏幕画海报并保存图片功能
Jul 25 Javascript
vue中使用v-model完成组件间的通信
Aug 22 Javascript
ES6 async、await的基本使用方法示例
Jun 06 Javascript
Vue ​v-model相关知识总结
Jan 28 Vue.js
从JQuery源码分析JavaScript函数的apply方法与call方法
Sep 25 #Javascript
JS小游戏之仙剑翻牌源码详解
Sep 25 #Javascript
JS小游戏之宇宙战机源码详解
Sep 25 #Javascript
JS小游戏之极速快跑源码详解
Sep 25 #Javascript
JS小游戏之象棋暗棋源码详解
Sep 25 #Javascript
我用的一些Node.js开发工具、开发包、框架等总结
Sep 25 #Javascript
jquery中使用循环下拉菜单示例代码
Sep 24 #Javascript
You might like
php分页代码学习示例分享
2014/02/20 PHP
php读取csv数据保存到数组的方法
2015/01/03 PHP
PHP删除指定目录中的所有目录及文件的方法
2015/02/26 PHP
PHP实现可添加水印与生成缩略图的图片处理工具类
2018/01/16 PHP
Javascript 网页黑白效果实现代码(兼容IE/FF等)
2010/04/23 Javascript
jQuery编写widget的一些技巧分享
2010/10/28 Javascript
javascript-简单的日历实现及Date对象语法介绍(附图)
2013/05/30 Javascript
js中的hasOwnProperty和isPrototypeOf方法使用实例
2014/06/06 Javascript
jquery 构造函数在表单提交过程中修改数据
2015/05/25 Javascript
js实现超简单的展开、折叠目录代码
2015/08/28 Javascript
JavaScript实现算术平方根算法-代码超简单
2015/09/11 Javascript
BootStrap Datepicker 插件修改为默认中文的实现方法
2017/02/10 Javascript
jQuery插件FusionCharts实现的3D柱状图效果实例【附demo源码下载】
2017/03/03 Javascript
JS实现向iframe中表单传值的方法
2017/03/24 Javascript
nodejs构建本地web测试服务器 如何解决访问静态资源问题
2017/07/14 NodeJs
详解react关于事件绑定this的四种方式
2018/03/09 Javascript
JS实现的RC4加密算法示例
2018/08/16 Javascript
移动端如何用下拉刷新的方式实现上拉加载
2018/12/10 Javascript
vue.js的简单自动求和计算实例
2019/11/08 Javascript
浅谈js中的attributes和Attribute的用法与区别
2020/07/16 Javascript
javascript中正则表达式语法详解
2020/08/07 Javascript
vue 实现把路由单独分离出来
2020/08/13 Javascript
[26:52]LGD vs EG 2018国际邀请赛小组赛BO2 第一场 8.17
2018/08/18 DOTA
python操作oracle的完整教程分享
2018/01/30 Python
Python字符串和正则表达式中的反斜杠('\')问题详解
2019/09/03 Python
Python使用贪婪算法解决问题
2019/10/22 Python
Python json解析库jsonpath原理及使用示例
2020/11/25 Python
python实现发送QQ邮件(可加附件)
2020/12/23 Python
python批量提取图片信息并保存的实现
2021/02/05 Python
HTML5本地数据库基础操作详解
2016/04/26 HTML / CSS
台湾深度自由行旅游平台:Tripbaa趣吧
2017/10/10 全球购物
Can a struct inherit from another class? (结构体能继承类吗)
2014/07/22 面试题
如何用JQuery进行表单验证
2013/05/29 面试题
将相和教学反思
2014/02/04 职场文书
道路交通事故人身损害赔偿协议书
2014/11/19 职场文书
团队执行力培训心得体会
2015/08/15 职场文书