如何用nodejs 把业务逻辑写的漂亮


背景:接触nodejs 写业务代码不久。 一直是phper

这个问题可能问的不是很恰当, 因为大部分时候可能代码写的好不好跟具体语言很多时候是无关的。
仅仅提出我的看法:

  1. 太多回调。 用回调倒是没关系,但是很多代码里回调是直接写的匿名函数。 匿名函数第一眼无法通过函数名理解其作用,其次是如果这个回调的匿名函数里如果逻辑太多,不利于重用。
  2. 异步, 显然用异步写的代码,肯定理解起来要困难。
  3. 很多函数会这样写 function (params, callback){ //...} ,把所有参数放到一个对象里传进去。因为总要留个参数位置给 callback , 要多写一个变量, 就会偷懒,把其他参数当作对象传递进去。 个人不是很喜欢这种作法,会让人猜不透这个函数有哪些变量?有什么作用?

大家会怎么去设计node的函数和回调,便于阅读理解?

node.js async callback

瘋花雪月夜 10 years, 2 months ago

promise co 多的是

肝不存在的 answered 10 years, 2 months ago

promise can save your ass

几千D花ひら answered 10 years, 2 months ago

saloy answered 10 years, 2 months ago

可瞅下我的 https://github.com/laomayi/nodeDHT 代码组织方式. 还有就是善用emitter这个东西, 比如:


 var events = require("events")
var emitter = new EventEmitter()

emitter.on("addUser", function(username) {
    //do something
});

emitter.on("delUser", function(uid) {
    // do something
})

app.get("/user/add/:username", function(req, res) {
    emitter.emit("addUser", req.params.username);
})

app.get("/user/del/:uid", function(req, res) {
    emitter.emit("delUser", req.params.uid);
})

这样你的代码就的回调就不多了, 看起来就像是PHP代码的自定函数随时调用一样,

最关键的是, 能避免这个蛋疼的语言就尽量避免.

JKing answered 10 years, 2 months ago

关于异步和回调,
Promise才是救世主
async.js是邪教

自己的业务逻辑一律用Promise表示结果,三方的库第一时间promisify,异常通过promise reject处理

顺便推荐Promise库bluebird
coffeescript和它派生的 coco LiveScript

晒最近刚写的一个简单小站代码 https://github.com/mcfog/higari
express, bluebird, 前后端分离,redis缓存
业务是爬虫扒别的站自己组织展示

下面是吐列表的一个controller,扒列表,循环扒详情组装好json输出


 getList = require \../ojisan/list
getDetail = require \../ojisan/detail

app <- ->
  module.exports = it

req, res, next <- app.get /^\/rank\/season\/(\d{4}-\d{1,2}).json/

getList "/anime/browser/airtime/#{req.params.0}"
.map (entry)->
  getDetail entry.id
  .then ->
    entry.detail = it

    entry

.then -> res.json it
.timeout 30_000
.catch ->
  console.error it
  res.end it.toString!

幻灭D帝王 answered 10 years, 2 months ago

前段时间的项目使用了Nodejs,中间经过过一次重构,基于Express框架,分享一下经验:

  1. 流程Promise化
    基于Nodejs的回调语法,你会写出大量下面这种代码:

 doAsync1(function () {
      doAsync2(function () {
        doAsync3(function () {
          doAsync4(function () {})
        })
      })
    })

这就是所谓的 “回调黑洞” 了,采用回调写法最大的问题有两个:

一是异常问题的处理,假设你的 doAsync4 依赖 doAsync3 的返回值,而 doAsync3 函数又依赖于 doAsync2 的返回值,如果 doAsync2 函数没有返回预想的结果,那么回调仍会继续执行,而如果你的代码里没有做良好的错误处理,可能代码会一直执行到 doAsync4 ,debug的痛苦可想而知。

二是业务流程的变更,现在我们假设要更改业务流程, doAsync2 发生在 doAsync1 之前,你的重构工作量有多少?

这时我们就要考虑使用 Promise 了,我并不打算在这里详细的介绍Promise,有趣的是SF就有对于Promise分析良好的系列文章: 深入理解Promise五部曲
以及目前常见的回调写法替代方案 Node.js回调黑洞全解:Async、Promise 和 Generator

上述代码如果用Promise来重构结果会是这样的:


 doAsync1
      .then(function (data1) {
        return data1
      })
      .then(function (data2) {
        return doAsync2(data2)
      })
      .then(function (data3) {
        return doAsync3(data3)
      })
      .then(function () {
        res.send('数据处理成功')
      })
      .error(function (error) {
        res.send('Error: ' + error)
      })

  1. 应用分层
    在应用中分出 Controller 层和 Model 层,不要把页面渲染和逻辑都塞到 Router 层。理想的结果是: Controller + Model + Router + Filter ,Filter层即是过滤,也可以理解为中间件,可以写一些过滤规则,比如最常见的要求用户登录:

 module.exports = {
      '/homepage': {
        get: ['auth.requireLogin', 'auth.requireAdmin']
      }
    }

在项目的上一次重构中,我砍掉了Router层,增加了一层API,将页面渲染和流程都放在Controller,而数据处理都在API,这样方便未来做数据验证和单元测验:

Controller层


 module.exports = {
      '/customer': {
        get: function (req, res) {
          var userInfo = req.body.data

          User
            .create(userInfo)
            .success(function () {})
        },
        post: function () {}
      }
    }

API层


 module.exports = {
      '/customer': {
        get: function () {
          User
            .info()
            .success(function (requiredData) {
              res.send(requiredData)
            })
        }
      }
    }

Model层取决于你用的数据库,流程的Promise化客观上要求了你的Model也要Promise化,Node上常见数据库的ORM都提供了Promise的写法,对应去看就好了。Express并不提供这种Restful路径的写法,我参考Rabbit框架(感谢芋头)基于这个插件改了改: rainbow

最后来看看成果,重构前的代码如下:

图片描述

重构之后(数据都放在API层了):

图片描述

那么问题来了,写Nodejs哪种写法强?

啃西瓜的魂 answered 10 years, 2 months ago

Your Answer