如何避免 node.js 中深度嵌套的代码?

Posted

技术标签:

【中文标题】如何避免 node.js 中深度嵌套的代码?【英文标题】:How do I avoid deeply nested code in node.js? 【发布时间】:2011-06-21 15:34:53 【问题描述】:

在 node.js 中,它是事件驱动的,所有 I/O 都是通过回调完成的。所以我最终编写了如下代码:

app.get('/test', function (req, res) 
  http.get('some/place', function (req1, res1) 
    if (res1.statusCode == 200) 
      res1.on('data', function (data) 
        http.get('other/place?q=' + data, function (req2, res2) 
          if (res2.statusCode == 200) 
            res2.on('data', function (data) 
              db.query(data).on('data', function (rows) 
                res.writeHead(200)
                res.end(JSON.stringify(rows))
              )
            )
          
        )
      )
    
  )
)

这甚至不包括错误处理。

我能做些什么来解开这个烂摊子?

【问题讨论】:

哇!好吧,嵌套好了! 可能重复:***.com/questions/4234619/… 【参考方案1】:

不要使用匿名函数。

编辑

您的代码甚至无效。您没有关闭大部分函数调用。

如果你切换到命名函数,它看起来像这样: 更新以反映关于全局命名空间的评论

(function () 
    app.get('/test', f0)

    function f0(req, res) 
      http.get('some/place', f1)
    

    function f1(req1, res1) 
        if (res1.statusCode == 200) 
          res1.on('data', f2)
        
     
    function f2(data) 
        http.get('other/place?q=' + data, f3)
    
    function f3(req2, res2) 
      if (res2.statusCode == 200) 
        res2.on('data', f4)
      
    

    function f4(data) 
          db.query(data).on('data', f5)
        

    function f5(rows) 
        res.writeHead(200)
        res.end(JSON.stringify(rows))
    
)()

【讨论】:

啊,这就是它没有正确突出显示语法的原因。固定。 @nornagon,这不会改变我的答案。 @nornagon,有一个非常简单的解决方案,我已经更新了我的示例。 此代码无效。讽刺。您不能立即调用未命名的函数声明。【参考方案2】:

您可以使用async 模块来避免这种情况。

【讨论】:

【参考方案3】:

我基于node-seq写了一个库,看起来是这样的:

app.get('/test', function (req, res) 
  Seq()
    .seq(function () 
      http.get('some/place', this.next)
    )
    .seq(function (req1, res1) 
      if (res1.statusCode == 200) 
        res1.on('data', this.next)
      
    )
    .seq(function (data) 
      http.get('other/place?q=' + data, this.next)
    )
    .seq(function (req2, res2) 
      if (res2.statusCode == 200) 
        res2.on('data', this.next)
      
    )
    .seq(function (data) 
      db.query(data).on('data', this.next)
    )
    .seq(function (rows) 
      res.writeHead(200)
      res.end(JSON.stringify(rows))
    )
)

代码是here。

此外,nodejs 邮件列表上还有一个lengthy discussion 与此问题相关。

Step 是另一个库。

【讨论】:

【参考方案4】:

请看Streamline;它是一个 javascript 预处理器,可让您编写简单的“流线型”代码并将其转换为大量回调代码。

【讨论】:

【参考方案5】:

清理这类事情的另一种(也许是更好的)方法是使用 EventEmitters 而不是回调。下面是一个例子,展示了几个正在使用的 EventEmitter:

 var events = require('events'),
    实用程序 = 需要('util');

    变种搜索=函数()
    “使用严格”;

    变量搜索,
        请求页面数据,
        使返回对象,
        发送结果,

        空对象 = ;

    events.EventEmitter.call(this);

    搜索 = 功能(查询)
        this.emit("requestPageData", query);
    ;

    requestPageData = 函数(查询)
        var 结果数组 = [];

        // 一些逻辑

        如果(......某些条件......)
            this.emit("makeReturnObject", resultsArray);
         别的 
            this.emit("sendResults", emptyObj);
        
    ;

    makeReturnObject = 函数(结果数组)
        var resultsObj = ;

        如果(磁铁阵列)

            // 一些逻辑

            this.emit("sendResults", resultsObj);
         别的 
            this.emit("sendResults", emptyObj);
        
    ;

    发送结果 = 函数 (obj) 
        // 最后,用 obj 做任何你想做的事
    ;

    this.on("requestPageData", requestPageData);

    this.on("makeReturnObject", makeReturnObject);

    this.on("sendResults", sendResults);

    this.search = 搜索;

;

util.inherits(搜索, events.EventEmitter);
module.exports = new Search();

【讨论】:

【参考方案6】:

您可以使用承诺。看看这个https://github.com/kriskowal/q

【讨论】:

以上是关于如何避免 node.js 中深度嵌套的代码?的主要内容,如果未能解决你的问题,请参考以下文章

如何在没有浏览器的 node.js 中使用 FormData?

如何避免 Node js 中强大功能的提前返回

如何在单个查询中返回 node.js mysql 中的嵌套 json

node.js 中的嵌套承诺是不是正常?

您如何在 Node.js + Express + Mongoose + Jade 中处理表单验证,尤其是嵌套模型

Node.js 中 For 循环中的 async.waterfall