NodeJs应用程序架构

第一次写技术类的文章,水平不高,才能有限,还希望大家多多指教。o(∩_∩)o 网上关于NodeJs的文章很多,不乏有很多的经典文章,但是据我个人观察,如何利用NodeJs本身特性来架构 一个高可维护性和可扩展性的应用程序的文章几乎没有。所以在这里我将分享一下我的小小经验。

一个糟糕的架构

下面的代码是一个关于登陆的实现(伪代码)。

  //当用户进行登陆时被调用
  function login (userName, pwd) {
    getUserData()                  //从数据中获取用户数据
    identifyAuth()                 //进行用户的认证
    getOtherData()                 //如果认证通过了,可能还需要拉去一些别的用户信息
                                   //例如用户的年龄,性别等详细信息....
    bindSession()                  //绑定用户的session,方便对用户进行后续的操作
  }

好了上面的一堆垃圾代码我已经写完了!是不是还不错?No! 为了大家看的更清晰一下,我只是用伪代码表示一下,毕竟我们谈的是架(zhuang)构(bi)嘛。如果 真的实现上述的代码,大量的回调是不可避免的。

带来的问题

  • 丑陋。如果添加新的功能需要在已经写的很棒的代码里插入一段罪恶的代码,可能破坏已有的和谐
  • Bug。当你的代码里有很多回调,功能又很多时,进行扩展时,出bug是早晚的事情
  • 低效。用上述代码为例。如果我想测试一个其他的功能,只需要获取用户的数据和各种详细的信息, 而并不想进行用户的认证。这时候就很蛋疼了,因为我竟然为了一个测试,需要去改我的后端代码, 杀了我吧~

解决方案

按照议论文的3段式结构,现在要开始解决问题了。 解决方案就是利用我大Node的事件机制。

首先,就不要把这一堆破烂堆在一个js文件里面啦,按功能分一下js文件。还是上面的代码,可以变成 如下几个js文件。

enter image description here

login,session和data几个js,里面就是上面所说的各种功能,无论是增加新的功能还是删除已有的功能,
此外,还需要让他们都继承Node的事件对象Event,然后将他们module.export出来。下面就是重点了, 一个main.js文件。他是整个架构的一个核心。略看一下 下面的伪代码,后面会有一段小的说明。

   var app = {}                          //声明一个全局的对象用来存储需要共享的变量
   app.get = function (key) {            //通过get来获取到你共享的对象
       ..........
   }   
   app.set = function (key, value) {     //通过set来设置你要共享的对象
       ..........
   } 

   //require 你的data,session,login 并初始化他们
   var data  = ........
   var session = ......
   var login = ........

   //将他们set到app变量中
   app.set('data', data)
   app.set('session', session)
   app.set('login', login)

   //进行事件的绑定
   sockets.io.on('connection', login.onLogin.bind(login)) //这里借用一下socket.io来触发
                                                         //登陆这个事件
   login.on('login', data.onLogin.bind(data))            //绑定login事件
   login.on('login', session.onLogin.bind(session))      

上面的代码可能有点儿小乱,简单说明一下。首先,会声明一个全局的变量app,用来存储实例化出来的需要 共享的对象,例如data和session。因为有时候需要在data中调用session对象的属性和方法,同app这个 相当于索引器的对象,可以方便的进行调用。接着进行事件的绑定,当connection事件触发后,login对象 的onLogin方法会调用,方法内会emit一个login事件,这个事件将直接触发下面绑定的2个事件。从而达到 获取用户数据和绑定session的目的。上面identifyAuth这个方法我没有提到(因为我忘了...),其实 他也可以拿出来,绑定login这个事件。所以只要是和login相关的任何方法,你都可以绑定这个事件。而 只要login这个事件被emit,他们就都会触发。

这样做的目的是可以比较好的进行解耦,如果我不想认证,不想获取data,只需要简单的将这个事件绑定 注释掉,一切的就ok了,不用改任何的代码,而我想增加任何的功能,只需要找到对应的事件,或者定义 相应的事件,进行绑定,就搞定了。而模块之间的属性和方法的获取,只需要通过app进行一键get即可。

这是我的处女作,如果有写的不好的地方请大家多多指教。 最后感谢m老板的催稿,让我能迈出技术博客的第一步~ ps:m老板一百块都不给我,好坏的~~~

2014.11.9