Node.JS

Node.js最佳实践

 这是有关Node.js的代码风格 开发流程等实战中的最佳实践。这些最佳实践能够帮助你成为更好的Node.js开发人员,Node.js因为是基于事件的开发模式,不同于平常基于线程的顺序编程,如果按照老的传统的编程习惯编写Node.js代码会导致很多问题,Node.js成也回调败也回调,过多使用回调会陷入回嵌套调陷阱,代码难以阅读,同时,Node.js是单线程,适合非CPU耗费的应用,比如IO读写转发,网页浏览等等,如何避免一些CPU繁重代码导致整体堵塞也是编程中应该注意的问题。

 

代码风格篇

回调约定

 模块应该首先暴露error-first错误优先的回调接口。

 应该如下:

module.exports = function (dragonName, callback) {  
   // 做一些事情
  var dragon = createDragon(dragonName); 
 
   // 注意下面,第一个参数应该是抛出的错误error
   //这里是空
   // 如果有错误发生,抛出错误error
  return callback(null, dragon); 
} 

 

总是在回调函数中检查错误

 为了解释这点,首先我们看看一个错误的案例,然后看问题出在哪里,如何解决它。

//这个案例是错的,我们稍后展示如何解决
 var fs = require('fs'); 
 
function readJSON(filePath, callback) {  
  fs.readFile(filePath, function(err, data) {  
    callback(JSON.parse(data)); 
  }); 
} 
 
readJSON('./package.json', function (err, pkg) { ... } 

 

 readJSON函数的问题是没有检查错误,如果在执行时发生错误,你应该总要检查它们。下面是解决后的版本:

function readJSON(filePath, callback) {  
  fs.readFile(filePath, function(err, data) { 
     // 如果有错误发生,这里我们进行检查
    if (err) { 
       // 将错误传递给callback函数
       // 记住这就是: error-first callbacks
      callback(err); 
    } 
 
     // no error, pass a null and the JSON
    callback(null, JSON.parse(data)); 
  }); 
} 

 

总是返回回调

 上述代码还是有一个问题,如果有错误Error发生,那么执行if中的语句callback函数,如果这个这个callback函数一直执行下去不会停止或返回,那么就导致很多不可预料的事情发生,所以,我们必须增加一个return,回调必须返回,否则执行顺序走叉了,回不来了。

function readJSON(filePath, callback) {  
  fs.readFile(filePath, function(err, data) { 
    if (err) { 
      return callback(err); //注意这里是返回
    } 
 
    return callback(null, JSON.parse(data)); //这里是返回
  }); 
} 

 

只在同步代码中使用try-catch

 这里我们关注上面代码中有一个JSON.parse,这个函数在不能分析有效JSON格式情况下可能会抛出exception出错。

 因为JSON.parse是同步发生,也就是执行到这个函数时,如果有错误就会立即发生,一旦发生就影响我们当前的主执行顺序,我们需要使用try-catch包住这段代码,注意,这只能在同步代码中使用,也就是主顺序代码中使用,在回调函数中使用是不会工作的,回调函数中出错是作为第一个参数返回,error-first callback。

function readJSON(filePath, callback) {  
  fs.readFile(filePath, function(err, data) { 
    var parsedJson; 
 
     // 处理 error
    if (err) { 
       return callback(err); 
    } 
 
     // 解析Parse JSON
    try { 
      parsedJson = JSON.parse(data); 
    } catch (exception) { 
      return callback(exception); 
    } 
 
     // 一切ok
    return callback(null, parsedJson); 
  }); 
} 

 

避免this和new

 在Node中绑定特定的上下文场景是不好的,因为Node包含了很多回调函数的传送,大量使用高阶函数来管理控制流程,用函数风格会省去很多麻烦,当然,还是有很多情况使用prototypes 对象方式是有效的,但是如果可能还是要避免它们。

 

创建小的模块

 以Unix方式来实现Node编码:

开发者建立程序时,应该是一一个个部分通过良好定义的接口连接在一起,这样问题会容易定位,程序的部分在将来需要支持新功能时能够替代。

 不要建立Deathstars 死亡之星,只有瞬间的闪耀便消失了,一个模块应当只做一件事。

 

使用好的异步模式

 推荐使用async框架

 

错误处理

 错误处理分为操作错误和编程错误。

 (一)操作错误:操作错误是运行时错误,也会发生在编写很良好的应用中,因为它们不是bug,而是系统或远程服务的问题,如:

  • 请求过时
  • 系统内存出错out of memory
  • 无法连接到远程服务

 那么如何处理操作错误呢?依赖于操作错误的类型,可以做以下几件事:

  • 试图解决错误,如果文件丢失,你需要首先创建一个
  • 重试操作,网络连接超时多试几次
  • 当处理用户客户端的输入时告诉客户端,有些不正常,但是能用。
  • 流程崩溃,比如应用无法读取配置文件等。

 无论如何,进行日志记录和分析是最重要的。

 (二)编程错误:编程错误是bug,下面情况你应该努力避免,如:

  • 没有使用回调函数调用一个异步函数(无法异步函数处理错误)
  • 不能读取错误: undefined

 解决编程错误是让它们早点出现,这些Bug你不知道将来会在什么时候出现,通过测试等让其尽早被发现,在运行生产环境,需要有一个流程控制系统能够在应用崩溃时重新启动应用,如 supervisord 或 monit.

 

下页

Node.js编程之道

美国航空航天局NASA的JavaScript编码规范